Пример #1
0
/* Write host data to host file */
static int write_hosts(struct daemon_data *d) {
    struct host *h;
    int r = 0;
    assert(d);

    rs_log_info("writing zeroconf data.\n");

    if (generic_lock(d->fd, 1, 1, 1) < 0) {
        rs_log_crit("lock failed: %s\n", strerror(errno));
        return -1;
    }

    if (lseek(d->fd, 0, SEEK_SET) < 0) {
        rs_log_crit("lseek() failed: %s\n", strerror(errno));
        return -1;
    }

    if (ftruncate(d->fd, 0) < 0) {
        rs_log_crit("ftruncate() failed: %s\n", strerror(errno));
        return -1;
    }

    remove_duplicate_services(d);

    for (h = d->hosts; h; h = h->next) {
        char t[256], a[AVAHI_ADDRESS_STR_MAX];

        if (h->resolver)
            /* Not yet fully resolved */
            continue;
	if (h->address.proto == AVAHI_PROTO_INET6)
	    snprintf(t, sizeof(t), "[%s]:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus);
	else
	    snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus);

        if (dcc_writex(d->fd, t, strlen(t)) != 0) {
            rs_log_crit("write() failed: %s\n", strerror(errno));
            goto finish;
        }
    }

    r = 0;

finish:

    generic_lock(d->fd, 1, 0, 1);
    return r;

};
Пример #2
0
/**
 * 装载TTA音乐文件 
 *
 * @param spath 短路径名
 * @param lpath 长路径名
 *
 * @return 成功时返回0
 */
static int tta_load(const char *spath, const char *lpath)
{
	__init();

	if (tta_read_tag(spath) != 0) {
		__end();
		return -1;
	}

	if (g_buff != NULL) {
		free(g_buff);
		g_buff = NULL;
	}
	g_buff = calloc(TTA_BUFFER_SIZE, sizeof(*g_buff));
	if (g_buff == NULL) {
		__end();
		return -1;
	}

	if (open_tta_file(spath, &ttainfo, 0, g_io_buffer_size) < 0) {
		dbg_printf(d, "TTA Decoder Error - %s", get_error_str(ttainfo.STATE));
		close_tta_file(&ttainfo);
		return -1;
	}

	if (player_init(&ttainfo) != 0) {
		__end();
		return -1;
	}

	if (ttainfo.BPS == 0) {
		__end();
		return -1;
	}

	g_info.samples = ttainfo.DATALENGTH;
	g_info.duration = (double) ttainfo.LENGTH;
	g_info.sample_freq = ttainfo.SAMPLERATE;
	g_info.channels = ttainfo.NCH;
	g_info.filesize = ttainfo.FILESIZE;

	if (xAudioInit() < 0) {
		__end();
		return -1;
	}

	if (xAudioSetFrequency(ttainfo.SAMPLERATE) < 0) {
		__end();
		return -1;
	}

	xAudioSetChannelCallback(0, tta_audiocallback, NULL);

	generic_lock();
	g_status = ST_LOADED;
	generic_unlock();

	return 0;
}
Пример #3
0
/**
 * 处理快进快退
 *
 * @return
 * - -1 should exit
 * - 0 OK
 */
static int handle_seek(void)
{
	if (g_status == ST_FFORWARD) {
		generic_lock();
		g_status = ST_PLAYING;
		generic_unlock();
		generic_set_playback(true);
		mp3_seek_seconds(g_play_time + g_seek_seconds);
	} else if (g_status == ST_FBACKWARD) {
		generic_lock();
		g_status = ST_PLAYING;
		generic_unlock();
		generic_set_playback(true);
		mp3_seek_seconds(g_play_time - g_seek_seconds);
	}

	return 0;
}
Пример #4
0
int generic_pause(void)
{
	generic_lock();
	generic_set_playback(false);
	g_status = ST_PAUSED;
	generic_unlock();

	return 0;
}
Пример #5
0
int generic_play(void)
{
	generic_lock();
	generic_set_playback(true);
	g_status = ST_PLAYING;
	generic_unlock();

	return 0;
}
Пример #6
0
/**
 * 停止MP3音乐文件的播放,销毁资源等
 *
 * @note 可以在播放线程中调用
 *
 * @return 成功时返回0
 */
static int __end(void)
{
	xAudioEndPre();

	g_play_time = 0.;
	generic_lock();
	g_status = ST_STOPPED;
	generic_unlock();

	return 0;
}
Пример #7
0
int generic_resume(const char *spath, const char *lpath)
{
	generic_lock();
	g_status = g_suspend_status;

	if (g_status == ST_PLAYING)
		generic_set_playback(true);

	generic_unlock();
	g_suspend_status = ST_LOADED;

	return 0;
}
Пример #8
0
/**
 * 快退音乐文件
 *
 * @param sec 秒数
 *
 * @return 成功时返回0
 */
int generic_fbackward(int sec)
{
	generic_lock();
	if (g_status == ST_PLAYING || g_status == ST_PAUSED
		|| g_status == ST_FFORWARD)
		g_status = ST_FBACKWARD;

	g_seek_seconds = sec;

	xrRtcGetCurrentTick((u64 *) & g_last_seek_tick);
	g_last_seek_is_forward = false;
	g_seek_count++;
	generic_unlock();

	return 0;
}
Пример #9
0
/**
 * 初始化驱动变量资源等
 *
 * @return 成功时返回0
 */
static int __init(void)
{
	generic_init();

	generic_lock();
	g_status = ST_UNKNOWN;
	generic_unlock();

	g_buff_frame_size = g_buff_frame_start = 0;
	g_seek_seconds = 0;

	g_play_time = 0.;

	g_samples_decoded = g_tta_data_offset = 0;
	memset(&g_info, 0, sizeof(g_info));

	return 0;
}
Пример #10
0
/**
 * 初始化驱动变量资源等
 *
 * @return 成功时返回0
 */
static int __init(void)
{
	generic_init();

	generic_lock();
	g_status = ST_UNKNOWN;
	generic_unlock();

	memset(&g_inst_br, 0, sizeof(g_inst_br));
	memset(g_input_buff, 0, sizeof(g_input_buff));
	g_buff_frame_size = g_buff_frame_start = 0;
	g_seek_seconds = 0;

	g_play_time = 0.;
	memset(&mp3info, 0, sizeof(mp3info));
	memset(&g_info, 0, sizeof(g_info));

	return 0;
}
Пример #11
0
static int mp3_load(const char *spath, const char *lpath)
{
	int ret;

	__init();

	dbg_printf(d, "%s: loading %s", __func__, spath);
	g_status = ST_UNKNOWN;

	mp3_data.use_buffer = true;

	mp3_data.fd = xrIoOpen(spath, PSP_O_RDONLY, 0777);

	if (mp3_data.fd < 0)
		return -1;

	g_info.filesize = xrIoLseek(mp3_data.fd, 0, PSP_SEEK_END);
	xrIoLseek(mp3_data.fd, 0, PSP_SEEK_SET);
	mp3_data.size = g_info.filesize;

	if (g_info.filesize < 0)
		return g_info.filesize;

	xrIoLseek(mp3_data.fd, 0, PSP_SEEK_SET);

	mad_stream_init(&stream);
	mad_frame_init(&frame);
	mad_synth_init(&synth);

	if (use_me) {
		if ((ret = me_init()) < 0) {
			dbg_printf(d, "me_init failed: %d", ret);
			use_me = false;
		}
	}

	mp3info.check_crc = check_crc;
	mp3info.have_crc = false;

	if (use_brute_method) {
		if (read_mp3_info_brute(&mp3info, &mp3_data) < 0) {
			__end();
			return -1;
		}
	} else {
		if (read_mp3_info(&mp3info, &mp3_data) < 0) {
			__end();
			return -1;
		}
	}

	g_info.channels = mp3info.channels;
	g_info.sample_freq = mp3info.sample_freq;
	g_info.avg_bps = mp3info.average_bitrate;
	g_info.samples = mp3info.frames;
	g_info.duration = mp3info.duration;

	generic_readtag(&g_info, spath);

	if (mp3_data.use_buffer) {
		SceOff cur = xrIoLseek(mp3_data.fd, 0, PSP_SEEK_CUR);

		xrIoClose(mp3_data.fd);
		mp3_data.fd = -1;
		mp3_data.r = buffered_reader_open(spath, g_io_buffer_size, 1);

		if (mp3_data.r == NULL) {
			__end();
			return -1;
		}

		buffered_reader_seek(mp3_data.r, cur);
	}

	dbg_printf(d, "[%d channel(s), %d Hz, %.2f kbps, %02d:%02d%sframes %d%s]",
			   g_info.channels, g_info.sample_freq,
			   g_info.avg_bps / 1000,
			   (int) (g_info.duration / 60), (int) g_info.duration % 60,
			   mp3info.frameoff != NULL ? ", frame table, " : ", ",
			   g_info.samples, mp3info.have_crc ? ", crc passed" : "");

#ifdef _DEBUG
	if (mp3info.lame_encoded) {
		char lame_method[80];
		char encode_msg[80];

		switch (mp3info.lame_mode) {
			case ABR:
				STRCPY_S(lame_method, "ABR");
				break;
			case CBR:
				STRCPY_S(lame_method, "CBR");
				break;
			case VBR:
				SPRINTF_S(lame_method, "VBR V%1d", mp3info.lame_vbr_quality);
				break;
			default:
				break;
		}

		if (mp3info.lame_str[strlen(mp3info.lame_str) - 1] == ' ')
			SPRINTF_S(encode_msg, "%s%s", mp3info.lame_str, lame_method);
		else
			SPRINTF_S(encode_msg, "%s %s", mp3info.lame_str, lame_method);
		dbg_printf(d, "[ %s ]", encode_msg);
	}
#endif

	ret = xAudioInit();

	if (ret < 0) {
		__end();
		return -1;
	}

	ret = xAudioSetFrequency(g_info.sample_freq);
	if (ret < 0) {
		__end();
		return -1;
	}

	g_buff = xAudioAlloc(0, BUFF_SIZE);

	if (g_buff == NULL) {
		__end();
		return -1;
	}

	if (use_me)
		xAudioSetChannelCallback(0, memp3_audiocallback, NULL);
	else
		xAudioSetChannelCallback(0, mp3_audiocallback, NULL);

	generic_lock();
	g_status = ST_LOADED;
	generic_unlock();

	return 0;
}
Пример #12
0
/* Get the host list from zeroconf */
int dcc_zeroconf_add_hosts(struct dcc_hostdef **ret_list, int *ret_nhosts, int n_slots, struct dcc_hostdef **ret_prev) {
    char host_file[PATH_MAX], lock_file[PATH_MAX], *s = NULL;
    int lock_fd = -1, host_fd = -1;
    int fork_daemon = 0;
    int r = -1;
    char *dir;
    struct stat st;

    if (get_zeroconf_dir(&dir) != 0) {
        rs_log_crit("failed to get zeroconf dir.\n");
        goto finish;
    }

    snprintf(lock_file, sizeof(lock_file), "%s/lock", dir);
    snprintf(host_file, sizeof(host_file), "%s/hosts", dir);

    /* Open lock file */
    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
        goto finish;
    }

    /* Try to lock the lock file */
    if (generic_lock(lock_fd, 1, 1, 0) >= 0) {
        /* The lock succeeded => there's no daemon running yet! */
        fork_daemon = 1;
        generic_lock(lock_fd, 1, 0, 0);
    }

    close(lock_fd);

    /* Shall we fork a new daemon? */
    if (fork_daemon) {
        pid_t pid;

        rs_log_info("Spawning zeroconf daemon.\n");

        if ((pid = fork()) == -1) {
            rs_log_crit("fork() failed: %s\n", strerror(errno));
            goto finish;
        } else if (pid == 0) {
            int fd;
            /* Child */

            /* Close file descriptors and replace them by /dev/null */
            close(0);
            close(1);
            close(2);
            fd = open("/dev/null", O_RDWR);
            assert(fd == 0);
            fd = dup(0);
            assert(fd == 1);
            fd = dup(0);
            assert(fd == 2);

#ifdef HAVE_SETSID
            setsid();
#endif

            chdir("/");
            rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
            _exit(daemon_proc(host_file, lock_file, n_slots));
        }

        /* Parent */

        /* Wait some time for initial host gathering */
        usleep(1000000);         /* 1000 ms */
    }

    /* Open host list read-only */
    if ((host_fd = open(host_file, O_RDONLY)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
        goto finish;
    }

    /* A read lock */
    if (generic_lock(host_fd, 0, 1, 1) < 0) {
        rs_log_crit("lock failed: %s\n", strerror(errno));
        goto finish;
    }

    /* Get file size */
    if (fstat(host_fd, &st) < 0) {
        rs_log_crit("stat() failed: %s\n", strerror(errno));
        goto finish;
    }

    if (st.st_size >= MAX_FILE_SIZE) {
        rs_log_crit("file too large.\n");
        goto finish;
    }

    /* read file data */
    s = malloc((size_t) st.st_size+1);
    assert(s);

    if (dcc_readx(host_fd, s, (size_t) st.st_size) != 0) {
        rs_log_crit("failed to read from file.\n");
        goto finish;
    }
    s[st.st_size] = 0;

    /* Parse host data */
    if (dcc_parse_hosts(s, host_file, ret_list, ret_nhosts, ret_prev) != 0) {
        rs_log_crit("failed to parse host file.\n");
        goto finish;
    }

    r = 0;

finish:
    if (host_fd >= 0) {
        generic_lock(host_fd, 0, 0, 1);
        close(host_fd);
    }

    free(s);

    return r;
}
Пример #13
0
/* The main function of the background daemon */
static int daemon_proc(const char *host_file, const char *lock_file, int n_slots) {
    int ret = 1;
    int lock_fd = -1;
    struct daemon_data d;
    time_t clip_time;
    int error;
    char machine[64], version[64], stype[128];

    rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);

    /* Prepare daemon data structure */
    d.fd = -1;
    d.hosts = NULL;
    d.n_slots = n_slots;
    d.simple_poll = NULL;
    d.browser = NULL;
    d.client = NULL;
    clip_time = time(NULL);

    rs_log_info("Zeroconf daemon running.\n");

    /* Open daemon lock file and lock it */
    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
        goto finish;
    }

    if (generic_lock(lock_fd, 1, 1, 0) < 0) {
        /* lock failed, there's probably already another daemon running */
        goto finish;
    }

    /* Open host file */
    if ((d.fd = open(host_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
        goto finish;
    }

    /* Clear host file */
    write_hosts(&d);

    if (!(d.simple_poll = avahi_simple_poll_new())) {
        rs_log_crit("Failed to create simple poll object.\n");
        goto finish;
    }

    if (!(d.client = avahi_client_new(
                  avahi_simple_poll_get(d.simple_poll),
                  0,
                  client_callback,
                  &d,
                  &error))) {
        rs_log_crit("Failed to create Avahi client object: %s\n", avahi_strerror(error));
        goto finish;
    }

    if (dcc_get_gcc_version(version, sizeof(version)) &&
        dcc_get_gcc_machine(machine, sizeof(machine))) {

        dcc_make_dnssd_subtype(stype, sizeof(stype), version, machine);
    } else {
        rs_log_warning("Warning, failed to get CC version and machine type.\n");

        strncpy(stype, DCC_DNS_SERVICE_TYPE, sizeof(stype));
        stype[sizeof(stype)-1] = 0;
    }

    rs_log_info("Browsing for '%s'.\n", stype);

    if (!(d.browser = avahi_service_browser_new(
                  d.client,
                  AVAHI_IF_UNSPEC,
                  AVAHI_PROTO_UNSPEC,
                  stype,
                  NULL,
                  0,
                  browse_reply,
                  &d))) {
        rs_log_crit("Failed to create service browser object: %s\n", avahi_strerror(avahi_client_errno(d.client)));
        goto finish;
    }

    /* Check whether the host file has been used recently */
    while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) {

        /* Iterate the main loop for 5s */
        if (avahi_simple_poll_iterate(d.simple_poll, 5000) != 0) {
            rs_log_crit("Event loop exited abnormaly.\n");
            goto finish;
        }
    }

    /* Wer are idle */
    rs_log_info("Zeroconf daemon unused.\n");

    ret = 0;

finish:

    /* Cleanup */
    if (lock_fd >= 0) {
        generic_lock(lock_fd, 1, 0, 0);
        close(lock_fd);
    }

    if (d.fd >= 0)
        close(d.fd);

    while (d.hosts) {
        struct host *h = d.hosts;
        d.hosts = d.hosts->next;
        free_host(h);
    }

    if (d.client)
        avahi_client_free(d.client);

    if (d.simple_poll)
        avahi_simple_poll_free(d.simple_poll);

    rs_log_info("zeroconf daemon ended.\n");

    return ret;
}
Пример #14
0
/**
 * TTA音乐播放回调函数,
 * 负责将解码数据填充声音缓存区
 *
 * @note 声音缓存区的格式为双声道,16位低字序
 *
 * @param buf 声音缓冲区指针
 * @param reqn 缓冲区帧大小
 * @param pdata 用户数据,无用
 */
static int tta_audiocallback(void *buf, unsigned int reqn, void *pdata)
{
	int avail_frame;
	int snd_buf_frame_size = (int) reqn;
	int ret;
	double incr;
	signed short *audio_buf = buf;

	UNUSED(pdata);

	if (g_status != ST_PLAYING) {
		if (g_status == ST_FFORWARD) {
			g_play_time += g_seek_seconds;
			if (g_play_time >= g_info.duration) {
				__end();
				return -1;
			}
			generic_lock();
			g_status = ST_PLAYING;
			generic_set_playback(true);
			generic_unlock();
			tta_seek_seconds(g_play_time);
		} else if (g_status == ST_FBACKWARD) {
			g_play_time -= g_seek_seconds;
			if (g_play_time < 0.) {
				g_play_time = 0.;
			}
			generic_lock();
			g_status = ST_PLAYING;
			generic_set_playback(true);
			generic_unlock();
			tta_seek_seconds(g_play_time);
		}
		xAudioClearSndBuf(buf, snd_buf_frame_size);
		xrKernelDelayThread(100000);
		return 0;
	}

	while (snd_buf_frame_size > 0) {
		avail_frame = g_buff_frame_size - g_buff_frame_start;

		if (avail_frame >= snd_buf_frame_size) {
			send_to_sndbuf(audio_buf,
						   &g_buff[g_buff_frame_start * g_info.channels],
						   snd_buf_frame_size, g_info.channels);
			g_buff_frame_start += snd_buf_frame_size;
			audio_buf += snd_buf_frame_size * 2;
			snd_buf_frame_size = 0;
		} else {
			send_to_sndbuf(audio_buf,
						   &g_buff[g_buff_frame_start * g_info.channels],
						   avail_frame, g_info.channels);
			snd_buf_frame_size -= avail_frame;
			audio_buf += avail_frame * 2;

			if (g_samples_decoded >= g_info.samples) {
				__end();
				return -1;
			}
			ret = get_samples((byte *) g_buff);
			if (ret <= 0) {
				__end();
				return -1;
			}

			g_buff_frame_size = ret;
			g_buff_frame_start = 0;

			incr = (double) (g_buff_frame_size) / g_info.sample_freq;
			g_play_time += incr;

			g_samples_decoded += g_buff_frame_size;
		}
	}

	return 0;
}