/*
* Copyright (c) 2011- Osmo Antero.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 3 of the License (GPL3), or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Library General Public License 3 for more details.
*
* You should have received a copy of the GNU Library General Public
* License 3 along with this program; if not, see /usr/share/common-licenses/GPL file
* or .
*/
#include
#include
#include
#include
#include
#include
#include
#include "dconf.h"
#include "log.h"
#include "utility.h"
#include "support.h"
#include "dbus-player.h"
#include "audio-sources.h"
// MPRIS2 compliant players.
#include "dbus-mpris2.h"
// Send commands to rec-manager.c
#include "rec-manager-struct.h"
// rec-manager.c
#include "rec-manager.h"
// List of players
static GHashTable *g_player_list = NULL;
static void dbus_player_disconnect_signals();
static void dbus_player_clear_list();
static void dbus_player_get_saved();
static void dbus_player_save(MediaPlayerRec *pl);
static void dbus_player_delete_saved(const gchar *service_name);
static gboolean dbus_player_msg_is_duplicate(MediaPlayerRec *player);
static const gchar *status_name(gint status) __attribute__((unused));
gboolean add_player_to_list(gchar *desktop_file, gchar *service_name);
void dbus_player_init() {
LOG_DEBUG("Init dbus-player.c.\n");
g_player_list = NULL;
mpris2_module_init();
}
void dbus_player_exit() {
LOG_DEBUG("Clean up dbus-player.c.\n");
// Disconnect DBus signals for all Media Players
dbus_player_disconnect_signals();
// Clear the player list
dbus_player_clear_list();
mpris2_module_exit();
}
static RecorderCommand *convert_data(MediaPlayerRec *pl) {
// Convert MediaPlayerRec to RecorderCommand
if (!pl) return NULL;
TrackInfo *tr = &pl->track;
RecorderCommand *cmd = g_malloc0(sizeof(RecorderCommand));
cmd->title = g_strndup(tr->title, MPRIS_STRLEN);
cmd->artist = g_strndup(tr->artist, MPRIS_STRLEN); // Actually a list of artists separated by '\v' (should we remove '\v'?)
cmd->album = g_strndup(tr->album, MPRIS_STRLEN);
cmd->genre = g_strndup(tr->genre, MPRIS_STRLEN); // Actually a list of genres separated by '\v' (should we remove '\v'?)
cmd->albumArtist = g_strndup(tr->albumArtist, MPRIS_STRLEN); // Actually a list of albumArtists separated by '\v' (should we remove '\v'?)
cmd->url = g_strndup(tr->url, MPRIS_STRLEN);
cmd->artUrl = g_strndup(tr->artUrl, MPRIS_STRLEN);
cmd->trackId = g_strndup(tr->trackId, MPRIS_STRLEN);
cmd->trackNumber = tr->trackNumber;
cmd->discNumber = tr->discNumber;
cmd->trackLength = tr->trackLength;
cmd->trackPos = tr->trackPos;
cmd->flags = tr->flags;
if (tr->status == PLAYER_STATUS_PAUSED) {
cmd->type = RECORDING_PAUSE;
} else if (tr->status == PLAYER_STATUS_PLAYING) {
cmd->type = RECORDING_START;
} else if (tr->status == PLAYER_STATUS_NOTIFY_MSG) {
cmd->type = RECORDING_NOTIFY_MSG;
} else {
// tr.status == PLAYER_STATUS_CLOSED ||
// tr.status == PLAYER_STATUS_STOPPED
cmd->type = RECORDING_STOP;
}
return cmd;
}
static gboolean dbus_player_msg_is_duplicate(MediaPlayerRec *player) {
// Check if player->track (TrackInfo) is duplicate of the previous one.
// Return TRUE if duplicate, otherwise FALSE.
if (!player) return FALSE;
// Track info
TrackInfo *tr = &player->track;
// Track info
TrackInfo *prev_tr = &player->prev_track;
// Check if message is duplicate of previous one
//if (tr->trackLength != prev_tr->trackLength) return FALSE;
//if (tr->trackPos != prev_tr->trackPos) return FALSE;
if (tr->trackNumber != prev_tr->trackNumber) {
return FALSE;
}
if (tr->discNumber != prev_tr->discNumber) {
return FALSE;
}
if (tr->audioBitrate != prev_tr->audioBitrate) {
return FALSE;
}
if (str_compare(tr->title, prev_tr->title, FALSE)) {
return FALSE;
}
if (str_compare(tr->artist, prev_tr->artist, FALSE)) {
return FALSE;
}
if (str_compare(tr->album, prev_tr->album, FALSE)) {
return FALSE;
}
if (str_compare(tr->genre, prev_tr->genre, TRUE)) {
return FALSE;
}
if (str_compare(tr->albumArtist, prev_tr->albumArtist, FALSE)) {
return FALSE;
}
if (str_compare(tr->url, prev_tr->url, FALSE)) {
return FALSE;
}
//if (str_compare(tr->artUrl, prev_tr->artUrl)) return FALSE;
if (str_compare(tr->trackId, prev_tr->trackId, FALSE)) {
return FALSE;
}
if (str_compare(tr->contentCreated, prev_tr->contentCreated, FALSE)) {
return FALSE;
}
// This TrackInfo is 100% duplicate of the previous one
return TRUE;
}
void dbus_player_process_data(gpointer player_rec, gboolean restart) {
// Send message to the rec-manager.c
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
if (!player) return;
// Current track
TrackInfo *tr = &player->track;
// Previous track (saved track data)
TrackInfo *prev_tr = &player->prev_track;
// Got PLAYING message from media player?
if (tr->status == PLAYER_STATUS_PLAYING) {
// Note !
// Check if this message from DBus is duplicate of previous one.
// Some media players send numerous duplicate messages. Messages confuse audio recorder.
if (dbus_player_msg_is_duplicate(player)) {
// Increment duplicate msg count. This is just for debugging!.
player->msg_count++;
// Is recording paused?
gboolean is_paused = rec_manager_is_paused();
if (is_paused) {
LOG_PLAYER("%s: This DBus message (#%i) is duplicate of previous one. Continuing PAUSED recording.\n", player->app_name, player->msg_count+1);
// Continue paused recording
rec_manager_continue_recording();
} else {
LOG_PLAYER("%s: This DBus message (#%i) is duplicate of previous one, %s. Dropping this message.\n",
player->app_name, player->msg_count+1, status_name(tr->status));
}
// Is duplicate. Drop this message.
return;
}
// Start new recording
// Stop the player first?
if (restart ) { // || (tr->status == PLAYER_STATUS_STOP)
rec_manager_stop_recording();
}
// Save, remember this track for next time !
memcpy(prev_tr, tr, sizeof(TrackInfo));
// Set msg count to 1 (just for debugging)
player->msg_count = 1;
// Continues to LBL_1
}
// Got PAUSED message from media player?
if (tr->status == PLAYER_STATUS_PAUSED) {
// Do nothing.
// Continues to LBL_1
}
// Got STOPPED message from media player?
if (tr->status == PLAYER_STATUS_STOPPED) {
// Nullify prev_tr (forget lastly received track data)
memset(prev_tr, '\0', sizeof(TrackInfo));
}
// LBL_1:
// Debug:
//dbus_player_debug_print(player);
// Convert MediaPlayerRec to RecorderCommand
RecorderCommand *cmd = convert_data(player);
// Send this command to rec-manager queue.
// Rec-manager will free the cmd structure after processing.
rec_manager_send_command(cmd);
}
void dbus_player_player_changed(gchar *service_name) {
// Re-connect DBus signals/methods for the given service_name (Media Player etc.)
// Disconnect all signals/object methods
dbus_player_disconnect_signals();
// Get MediaPlayerRec for this service_name
MediaPlayerRec *player = dbus_player_lookup_service_name(service_name);
if (player && player->func_set_signals) {
LOG_PLAYER("Connect DBus signals for %s (%s).\n", player->app_name, player->service_name);
// Start application (Media Player, etc)
if (player->func_start_app) {
player->func_start_app(player);
}
// Connect signals so we receive track-changed/start/stop messages from this app (over DBus)
player->func_set_signals(player, TRUE); // TRUE=connect/register, FALSE=disconnect/unregister
// Save this player in GSettings so user doesn't need to refresh the combo manually.
dbus_player_save(player);
}
}
static void dbus_player_disconnect_signals() {
// Disconnect all signal-functions from the DBus
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init(&iter, g_player_list);
while (g_hash_table_iter_next(&iter, &key, &value)) {
MediaPlayerRec *player = (MediaPlayerRec*)value;
if (player && player->func_set_signals) {
// Disconnect signals
player->func_set_signals(player, FALSE); // FALSE=disconnect/unregister
}
}
}
GHashTable *dbus_player_get_list_ref() {
if (!g_player_list) {
g_player_list = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, dbus_player_delete_item);
}
return g_player_list;
}
static gboolean dbus_palyer_remove_node(gpointer key, gpointer value, gpointer user_data) {
// Return TRUE so this (key, value) pair gets removed and deleted.
return TRUE;
}
static void dbus_player_clear_list() {
// Delete the entire g_player_list
if (g_player_list) {
g_hash_table_foreach_remove(g_player_list, dbus_palyer_remove_node, NULL);
g_hash_table_unref(g_player_list);
}
g_player_list = NULL;
}
void dbus_player_delete_item(gpointer data) {
MediaPlayerRec *player = (MediaPlayerRec*)data;
if (!player) return;
LOG_PLAYER("dbus_player_delete_item: %s (%s).\n", player->app_name, player->service_name);
if (player->func_set_signals) {
// Disconnect signals
player->func_set_signals(player, FALSE); // TRUE=connect, FALSE=disconnect
}
if (G_IS_DBUS_PROXY(player->proxy)) {
g_object_unref(player->proxy);
}
player->proxy = NULL;
if (G_IS_DBUS_PROXY(player->prop_proxy)) {
g_object_unref(player->prop_proxy);
}
player->prop_proxy = NULL;
g_free(player->service_name);
g_free(player->desktop_file);
g_free(player->exec_cmd);
g_free(player->app_name);
g_free(player->icon_name);
g_free(player);
}
MediaPlayerRec *dbus_player_lookup_app_name(const gchar *app_name) {
// Lookup player by its application name (p->app_name).
// Typical app_names are "Amarok 2.3.2", "RhythmBox 2.3".
GHashTableIter iter;
gpointer key, value;
if (str_length(app_name, 1024) < 1) return NULL;
g_hash_table_iter_init(&iter, g_player_list);
while (g_hash_table_iter_next(&iter, &key, &value)) {
MediaPlayerRec *p = (MediaPlayerRec*)value;
if (!g_strcmp0(p->app_name, app_name)) {
return p;
}
}
return NULL;
}
MediaPlayerRec *dbus_player_lookup_service_name(const gchar *service_name) {
// Lookup player by its service name (p->service_name).
// "org.mpris.MediaPlayer2.Player.banshee" is a typical service_name.
GHashTableIter iter;
gpointer key, value;
if (str_length(service_name, 1024) < 1) return NULL;
g_hash_table_iter_init(&iter, g_player_list);
while (g_hash_table_iter_next(&iter, &key, &value)) {
MediaPlayerRec *p = (MediaPlayerRec*)value;
if (!g_strcmp0(p->service_name, service_name)) {
return p;
}
}
return NULL;
}
static const gchar *status_name(gint status) {
static gchar s[80];
s[0] = '\0';
switch (status) {
case PLAYER_STATUS_CLOSED:
g_sprintf(s, "Status:%d PLAYER_STATUS_CLOSED (not running)", status);
break;
case PLAYER_STATUS_STOPPED:
g_sprintf(s, "Status:%d PLAYER_STATUS_STOPPED", status);
break;
case PLAYER_STATUS_PAUSED:
g_sprintf(s, "Status:%d PLAYER_STATUS_PAUSED", status);
break;
case PLAYER_STATUS_PLAYING:
g_sprintf(s, "Status:%d PLAYER_STATUS_PLAYING", status);
break;
case PLAYER_STATUS_NOTIFY_MSG:
// Simply a msg to the GUI.
g_sprintf(s, "Status:%d PLAYER_STATUS_NOTIFY_MSG", status);
break;
default:
g_sprintf(s, "Unknown status:%d\n", status);
}
return &s[0];
}
void dbus_player_debug_print(MediaPlayerRec *p) {
if (!p) return;
LOG_PLAYER("------------------------------\n");
LOG_PLAYER("Player app name:%s\n", p->app_name);
LOG_PLAYER("Service name:%s\n", p->service_name);
LOG_PLAYER("Desktop file:%s.desktop\n", p->desktop_file);
LOG_PLAYER("Executable command:%s\n", p->exec_cmd);
TrackInfo *tr = &p->track;
LOG_PLAYER("%s\n", status_name(tr->status));
if (tr->status != PLAYER_STATUS_NOTIFY_MSG) {
LOG_PLAYER("Title:%s\n", tr->title);
LOG_PLAYER("Artist:%s\n", tr->artist);
LOG_PLAYER("Album:%s\n", tr->album);
LOG_PLAYER("Genre:%s\n", tr->genre);
LOG_PLAYER("AlbumArtist:%s\n", tr->albumArtist);
LOG_PLAYER("Url:%s\n", tr->url);
LOG_PLAYER("ArtUrl:%s\n", tr->artUrl);
LOG_PLAYER("TrackId:%s\n", tr->trackId);
LOG_PLAYER("ContentCreated:%s\n", tr->contentCreated);
LOG_PLAYER("Track length in microsecs:%ld\n", tr->trackLength);
LOG_PLAYER("Track pos in microsecs:%ld\n", tr->trackPos);
LOG_PLAYER("Flags:%d\n", tr->flags);
LOG_PLAYER("Msg count:%d\n", p->msg_count);
} else {
// Simply a msg to the GUI.
LOG_PLAYER("Message:%s\n", tr->title);
}
LOG_PLAYER("------------------------------\n");
}
GHashTable *dbus_player_get_player_list() {
// Clear the old list
dbus_player_clear_list();
// Populate the list.
// Detect players that follow the org.mpris.MediaPlayer2.* standard.
mpris2_detect_players();
// Add lastly used and saved players to the list
dbus_player_get_saved();
// Make sure the most popular players are in the list (on our target distros).
// Notice: Audio-recorder will automatically detect and remember the last used players.
// Start your media-player, then press [Refresh]-button at end of Source: listbox to detect it.
// You do not need to hard-code other, new players here.
// Add Rhythmbox manually (check if installed)
add_player_to_list("rhythmbox", "org.mpris.MediaPlayer2.rhythmbox");
return g_player_list;
}
gboolean add_player_to_list(gchar *desktop_file, gchar *service_name) {
// Add player manually to the list. Check if it's installed.
// Already in the list?
if (dbus_player_lookup_service_name(service_name)) return TRUE;
// New MediaPlayer record
MediaPlayerRec *player = mpris2_player_new(service_name);
// Set desktop file
player->desktop_file = g_strdup(desktop_file);
// Read rest from player's .desktop file
get_details_from_desktop_file(player, desktop_file);
// Find executable /usr/bin/exec_cmd
gchar *path = find_command_path(player->exec_cmd);
if (!path) {
// Not installed.
dbus_player_delete_item(player);
return FALSE;
}
g_free(path);
// Function to connect/disconnect event signals for this player
player->func_set_signals = mpris2_set_signals;
// Function to get track-info (album, title/song name/title, genre, etc.)
player->func_get_info = mpris2_get_metadata;
// Function to start/run the media player
player->func_start_app = mpris2_start_app;
// Function to check if this player is running
player->func_check_is_running = mpris2_service_is_running;
if (!dbus_player_lookup_app_name(player->app_name)) {
// Add to list
GHashTable *player_list = dbus_player_get_list_ref();
g_hash_table_insert(player_list, g_strdup(player->service_name), player);
} else {
// Duplicate or bad record. Free it.
dbus_player_delete_item(player);
}
return TRUE;
}
void dbus_player_send_notification(gchar *msg) {
RecorderCommand *cmd = g_malloc0(sizeof(RecorderCommand));
cmd->type = RECORDING_NOTIFY_MSG;
// Convey message in the title field
cmd->title = g_strndup(msg, MPRIS_STRLEN);
// Send command to rec-manager.c.
// It will free the cmd structure after processing.
rec_manager_send_command(cmd);
}
// --------------------------------------------------------------------
// Support functions to read/write values to "players/saved-player-list" in GSettings.
// --------------------------------------------------------------------
static void split_value(gchar *str, gchar **desktop_file, gchar **service_name) {
// Split str on "\t" and return the parts.
*desktop_file = NULL;
*service_name = NULL;
if (!str) return;
// Split on '\t'
gchar **args = g_strsplit(str, "\t", 3);
// We cope only 2 arguments
if (g_strv_length(args) != 2) {
goto LBL_1;
}
if (args && args[0]) {
*desktop_file = g_strdup(args[0]);
if (args[1]) {
*service_name = g_strdup(args[1]);
}
}
LBL_1:
// Delete args
g_strfreev(args);
}
gchar *get_base_name(gchar *service_name) {
// Take last part of service_name and return it.
// Eg. take "vlc" from "org.mpris.MediaPlayer2.vlc"
// Find last "."
gchar *pos = g_strrstr0(service_name, ".");
if (pos) {
return g_strdup(pos+1);
}
return NULL;
}
static void dbus_player_delete_saved(const gchar *service_name) {
// Delete service_name from GSettings.
// See dconf-editor, key: /apps/audio-recorder/players/players/saved-player-list
GList *list = NULL;
GList *new_list = NULL;
if (!service_name) return;
str_trim((gchar*)service_name);
// Get saved-player-list from GSettings.
const gchar *conf_key = "players/saved-player-list";
conf_get_string_list((gchar*)conf_key, &list);
GList *item = g_list_first(list);
while (item) {
// Take values. Eg: "amarok \t org.mpris.MediaPlayer2.amarok"
gchar *str = (gchar*)item->data;
gchar *desktop_file = NULL;
gchar *service = NULL;
// Split on '\t'
split_value(str, &desktop_file, &service);
// Service names match?
if (!g_strcmp0(service_name, service)) {
// Drop this node
;
} else {
// Keep this node
new_list = g_list_append(new_list, g_strdup(str));
}
g_free(desktop_file);
g_free(service);
item = g_list_next(item);
}
// Save changes to GSettings
conf_save_string_list((gchar*)conf_key, new_list);
// Free delete_list
str_list_free(new_list);
new_list = NULL;
// Free list
str_list_free(list);
list = NULL;
}
static void dbus_player_save(MediaPlayerRec *pl) {
// Save pl->app_name/pl->service_name to GSettings.
// See dconf-editor, key: /apps/audio-recorder/players/players/saved-player-list
GList *list = NULL;
if (!pl->service_name) return;
// Delete old value
dbus_player_delete_saved(pl->service_name);
// str must have format "vlc \t org.mpris.MediaPlayer2.vlc"
gchar *str = g_strdup_printf("%s\t%s", check_null(pl->desktop_file), pl->service_name);
// Get saved-player-list from Gsettings.
const gchar *conf_key = "players/saved-player-list";
conf_get_string_list((gchar*)conf_key, &list);
// Add new entry and save in GSettings/DConf
list = g_list_prepend(list, g_strdup(str));
conf_save_string_list((gchar*)conf_key, list);
#if defined(DEBUG_PLAYER) || defined(DEBUG_ALL)
LOG_PLAYER("----------------------------\n");
str_list_print("New, saved saved-player-list", list);
LOG_PLAYER("----------------------------\n");
#endif
// Free list
str_list_free(list);
list = NULL;
g_free(str);
}
static void dbus_player_get_saved() {
// Get saved-player-list from GSettings.
// See dconf-editor, key: /apps/audio-recorder/players/players/saved-player-list
const gchar *conf_key = "players/saved-player-list";
// Get list
GList *list = NULL;
conf_get_string_list((gchar*)conf_key, &list);
#if defined(DEBUG_PLAYER) || defined(DEBUG_ALL)
LOG_PLAYER("----------------------------\n");
str_list_print("Get saved-player-list", list);
LOG_PLAYER("----------------------------\n");
#endif
// Add saved & still existing media-players to the list
GList *item = g_list_first(list);
while (item) {
// Read values. Eg. "vlc \t org.mpris.MediaPlayer2.vlc"
gchar *str = (gchar*)item->data;
gchar *desktop_file = NULL;
gchar *service_name = NULL;
// Split on '\t'
split_value(str, &desktop_file, &service_name);
// We will not tolerate errors here.
// Wipe out the entire list if one line is bad (eg. it has older format)!
if (!(desktop_file && service_name)) {
g_free(desktop_file);
g_free(service_name);
conf_save_string_list((gchar*)conf_key, NULL);
goto LBL_1;
}
// Add media-player to the list (to be shown in the "Source:" listbox).
if (!add_player_to_list(desktop_file, service_name)) {
// It's probably uninstalled. Delete form GSettings too.
LOG_PLAYER("Player %s, (%s) removed from the list. It's probably uninstalled.\n",
desktop_file, service_name);
dbus_player_delete_saved(service_name);
}
g_free(desktop_file);
g_free(service_name);
item = g_list_next(item);
}
LBL_1: {
// Free list
str_list_free(list);
list = NULL;
}
}
void get_details_from_desktop_file(MediaPlayerRec *pl, const gchar *desktop_file) {
// Find AppInfo for the given .desktop file
// I assume here that .desktop filenames are in ascii (not multibyte) strings
if (!desktop_file) {
goto LBL_1;
}
gchar *s = NULL;
// Ends with ".desktop"?
if (g_str_has_suffix(desktop_file, ".desktop")) {
s = g_strdup(desktop_file);
} else {
// Add ".desktop"
s = g_strdup_printf("%s.desktop", desktop_file);
}
// Get GDesktopAppInfo from propgram.desktop file
GDesktopAppInfo *app_info = g_desktop_app_info_new(s);
gchar *found_str = NULL;
// .desktop file was found?
if (!G_IS_DESKTOP_APP_INFO(app_info)) {
// No. Search for it.
g_free(s); s = NULL;
// Find application's basename
// Eg. "amarok" of "org.kde.amarok"
gchar *p = strrchr(desktop_file, '.');
if (p && (str_length0(p) > 1)) {
s = g_strdup(p + 1);
} else {
s = g_strdup(desktop_file);
}
gchar ***results = g_desktop_app_info_search(s);
// results: gchar *results[][]
// results is a 2-dim array of gchar* strings, the first (i dimension) contains results (another array) for each search string we passed in (in s).
// Please see: https://developer.gnome.org/gio/stable/gio-Desktop-file-based-GAppInfo.html#g-desktop-app-info-search
gchar *s2 = g_strdup_printf("%s.desktop", s);
for (guint i=0; results && results[i] != NULL; i++) {
for (guint j=0; results[i][j] != NULL; j++) {
// Some nitpicking here
gchar *s1_down = g_ascii_strdown(results[i][j], str_length0(results[i][j]));
gchar *s2_down = g_ascii_strdown(s2, str_length0(s2));
if (g_strrstr(s1_down, s2_down)) {
// Probably safe with utf8 (multibyte)
// https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strrstr
found_str = g_strdup(results[i][j]);
}
g_free(s1_down);
g_free(s2_down);
if (found_str) {
break;
}
} // j...
} // i...
g_free(s2);
// Free gchar *results[][]
// Be carefull
for (guint i=0; results[i] != NULL; i++) {
g_strfreev(results[i]);
}
g_free(results);
results = NULL;
// Try again
if (found_str) {
// Load AppInfo
app_info = g_desktop_app_info_new(found_str);
}
}
g_free(found_str);
g_free(s);
// Do we have AppInfo?
if (!G_IS_DESKTOP_APP_INFO(app_info)) {
goto LBL_1;
}
// Read application title
const gchar *app_name = g_app_info_get_name(G_APP_INFO(app_info));
if (!app_name) {
app_name = g_app_info_get_display_name(G_APP_INFO(app_info));
}
pl->app_name = g_strdup(app_name);
// Read executable command and its arguments
pl->exec_cmd = g_strdup((gchar*)g_app_info_get_commandline(G_APP_INFO(app_info)));
pl->icon_name = g_desktop_app_info_get_string(app_info, "Icon");
if (!pl->icon_name){
pl->icon_name = g_strdup((gchar *)g_app_info_get_executable(G_APP_INFO(app_info)));
}
g_object_unref(app_info);
// Remove %U from the exec command.
// %u, %U in the exec command (.desktop file) is normally replaced by a file argument
// Some media players show an error if the file argument is empty
str_trim(pl->exec_cmd);
gchar *p = g_strrstr(pl->exec_cmd, "%U");
if (!p)
p = g_strrstr(pl->exec_cmd, "%u");
if (p)
*p = '\0';
LBL_1: {
// Basename
// Eg. take "vlc" from "org.mpris.MediaPlayer2.vlc"
gchar *base_name = get_base_name(pl->service_name);
// Make sure these values are set
if (!pl->app_name) {
pl->app_name = g_strdup(base_name);
}
if (!pl->desktop_file) {
pl->desktop_file = g_strdup(base_name);
}
if (!pl->exec_cmd) {
pl->exec_cmd = g_strdup(base_name);
}
if (!pl->exec_cmd) {
pl->exec_cmd = g_strdup(base_name);
}
if (!pl->icon_name) {
pl->icon_name = g_strdup(base_name);
}
g_free(base_name);
}
}
void dbus_player_reset_values(gchar *audio_source) {
// Reset audio_source's internal values (in dbus-player.c module).
// Get MediaPlayerRec for this audio_source (service name)
MediaPlayerRec *player = dbus_player_lookup_service_name(audio_source);
if (!player) {
return;
}
// Nullify player->prev_track (TrackInfo record).
// User has stopped recording from the GUI (Button or Menu),
// We must clear MediaPlayerRec`s prev_track record.
// User can later re-start recording from the media-player, and it is not counted as duplicate START_RECORDING message.
// This is important for some media players.
TrackInfo *tr = &player->prev_track;
memset(tr, '\0', sizeof(TrackInfo));
}