Пример #1
0
off_t term_control(mpg123_handle *fr, out123_handle *ao)
{
	offset = 0;
	debug2("control for frame: %li, enable: %i", (long)mpg123_tellframe(fr), term_enable);
	if(!term_enable) return 0;

	if(paused)
	{
		/* pause_cycle counts the remaining frames _after_ this one, thus <0, not ==0 . */
		if(--pause_cycle < 0)
			pause_recycle(fr);
	}

	do
	{
		off_t old_offset = offset;
		term_handle_input(fr, ao, stopped|seeking);
		if((offset < 0) && (-offset > framenum)) offset = - framenum;
		if(param.verbose && offset != old_offset)
			print_stat(fr,offset,ao);
	} while (!intflag && stopped);

	/* Make the seeking experience with buffer less annoying.
	   No sound during seek, but at least it is possible to go backwards. */
	if(offset)
	{
		if((offset = mpg123_seek_frame(fr, offset, SEEK_CUR)) >= 0)
		debug1("seeked to %li", (long)offset);
		else error1("seek failed: %s!", mpg123_strerror(fr));
		/* Buffer resync already happened on un-stop? */
		/* if(param.usebuffer) audio_drop(ao);*/
	}
	return 0;
}
Пример #2
0
void Mp3::onSeek(sf::Time timeOffset)
{
    sf::Lock lock(myMutex);

    if (myHandle)
        mpg123_seek_frame(myHandle, mpg123_timeframe(myHandle, timeOffset.asSeconds()), SEEK_SET);
}
Пример #3
0
JNIEXPORT jint JNICALL Java_com_axelby_mp3decoders_MPG123_seek
	(JNIEnv *env, jclass c, jlong handle, jfloat seconds)
{
    MP3File *mp3 = (MP3File *)handle;
    int err = mpg123_seek_frame(mp3->handle, (int) (seconds / mp3->secs_per_frame), SEEK_SET);
	if (err < 0)
		printerr("mpg123_seek_frame", err);
	return err;
}
Пример #4
0
int mpeg_seek(int fd, int offs_secs, int whence)
{
    int rv = -1;
    if((handle != NULL) && (fd != -1))
    {
        off_t seek_off = 0;
        seek_off = mpg123_timeframe(handle->mh, (double)offs_secs);
        if(offs_secs < 0)
        {
            mpg123_seek_frame(handle->mh, seek_off, whence);
        }
        else
        {
            mpg123_seek_frame(handle->mh, (seek_off), whence);
        }
        rv = 0;
    }
    return rv;
}
Пример #5
0
int GetMusicStatus()
{
	char buff[MAX_PATH] = {0};
	DWORD ret;

	_snprintf(buff, MAX_PATH, "%s\\\\%s", dir, fileInfo.cFileName);
	ret = mpg123_open(mh, buff);
	if(ret != MPG123_OK)
	{
		return 1;
	}

	mpg123_seek_frame(mh, lastFrame, SEEK_SET);
	return 0;
}
Пример #6
0
off_t term_control(mpg123_handle *fr, audio_output_t *ao)
{
	offset = 0;
debug1("control for frame: %li", (long)mpg123_tellframe(fr));
	if(!term_enable) return 0;

	if(paused)
	{
		/* pause_cycle counts the remaining frames _after_ this one, thus <0, not ==0 . */
		if(--pause_cycle < 0)
		{
			pause_recycle(fr);
			if(param.usebuffer)
			{
				while(paused && xfermem_get_usedspace(buffermem))
				{
					buffer_ignore_lowmem();
					term_handle_input(fr, ao, TRUE);
				}
				/* Undo the cycling offset if we are done with cycling. */
				if(!paused)	pause_uncycle();
			}
		}
	}

	do
	{
		term_handle_input(fr, ao, stopped|seeking);
		if((offset < 0) && (-offset > framenum)) offset = - framenum;
		if(param.verbose && offset != 0)
		print_stat(fr,offset,0);
	} while (stopped);

	/* Make the seeking experience with buffer less annoying.
	   No sound during seek, but at least it is possible to go backwards. */
	if(offset)
	{
		if((offset = mpg123_seek_frame(fr, offset, SEEK_CUR)) >= 0)
		debug1("seeked to %li", (long)offset);
		else error1("seek failed: %s!", mpg123_strerror(fr));
		/* Buffer resync already happened on un-stop? */
		/* if(param.usebuffer) buffer_resync();*/
	}
	return 0;
}
Пример #7
0
void plugin_seek(struct playerHandles *ph, int modtime){
	if(ph->dechandle==NULL){
		fprintf(stderr,"no dechandle");
		return;
	}

pthread_mutex_lock(&dechandle_lock);
	struct mp3Handles *h=(struct mp3Handles *)ph->dechandle;
	mpg123_seek_frame(h->m,mpg123_timeframe(h->m,(int)modtime),modtime?SEEK_CUR:SEEK_SET);


	if(modtime){
		h->total+=modtime;
		if(h->total<0)h->total=0;
	}
	else
		h->total=0;
pthread_mutex_unlock(&dechandle_lock);

	snd_clear(ph);
}
Пример #8
0
bool Mpg123Decoder::Seek(size_t offset, Origin origin) {
	finished = false;
	mpg123_seek_frame(handle.get(), offset, (int)origin);

	return true;
}
Пример #9
0
static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
{
	debug1("term_handle_key: %c", val);
	switch(tolower(val))
	{
	case MPG123_BACK_KEY:
		out123_pause(ao);
		out123_drop(ao);
		if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));

		if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0)
		error1("Seek to begin failed: %s", mpg123_strerror(fr));

		framenum=0;
	break;
	case MPG123_NEXT_KEY:
		out123_pause(ao);
		out123_drop(ao);
		next_track();
	break;
	case MPG123_NEXT_DIR_KEY:
		out123_pause(ao);
		out123_drop(ao);
		next_dir();
	break;
	case MPG123_QUIT_KEY:
		debug("QUIT");
		if(stopped)
		{
			stopped = 0;
			out123_pause(ao); /* no chance for annoying underrun warnings */
			out123_drop(ao);
		}
		set_intflag();
		offset = 0;
	break;
	case MPG123_PAUSE_KEY:
		paused=1-paused;
		out123_pause(ao); /* underrun awareness */
		out123_drop(ao);
		if(paused)
		{
			/* Not really sure if that is what is wanted
				 This jumps in audio output, but has direct reaction to pausing loop. */
			out123_param_float(ao, OUT123_PRELOAD, 0.);
			pause_recycle(fr);
		}
		else
			out123_param_float(ao, OUT123_PRELOAD, param.preload);
		if(stopped)
			stopped=0;
		if(param.verbose)
			print_stat(fr, 0, ao);
		else
			fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING);
	break;
	case MPG123_STOP_KEY:
	case ' ':
		/* TODO: Verify/ensure that there is no "chirp from the past" when
		   seeking while stopped. */
		stopped=1-stopped;
		if(paused) {
			paused=0;
			offset -= pause_cycle;
		}
		if(stopped)
			out123_pause(ao);
		else
		{
			if(offset) /* If position changed, old is outdated. */
				out123_drop(ao);
			/* No out123_continue(), that's triggered by out123_play(). */
		}
		if(param.verbose)
			print_stat(fr, 0, ao);
		else
			fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING);
	break;
	case MPG123_FINE_REWIND_KEY:
		seekmode(fr, ao);
		offset--;
	break;
	case MPG123_FINE_FORWARD_KEY:
		seekmode(fr, ao);
		offset++;
	break;
	case MPG123_REWIND_KEY:
		seekmode(fr, ao);
		  offset-=10;
	break;
	case MPG123_FORWARD_KEY:
		seekmode(fr, ao);
		offset+=10;
	break;
	case MPG123_FAST_REWIND_KEY:
		seekmode(fr, ao);
		offset-=50;
	break;
	case MPG123_FAST_FORWARD_KEY:
		seekmode(fr, ao);
		offset+=50;
	break;
	case MPG123_VOL_UP_KEY:
		mpg123_volume_change(fr, 0.02);
	break;
	case MPG123_VOL_DOWN_KEY:
		mpg123_volume_change(fr, -0.02);
	break;
	case MPG123_PITCH_UP_KEY:
	case MPG123_PITCH_BUP_KEY:
	case MPG123_PITCH_DOWN_KEY:
	case MPG123_PITCH_BDOWN_KEY:
	case MPG123_PITCH_ZERO_KEY:
	{
		double new_pitch = param.pitch;
		switch(val) /* Not tolower here! */
		{
			case MPG123_PITCH_UP_KEY:    new_pitch += MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BUP_KEY:   new_pitch += MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_DOWN_KEY:  new_pitch -= MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_ZERO_KEY:  new_pitch = 0.0; break;
		}
		set_pitch(fr, ao, new_pitch);
		fprintf(stderr, "New pitch: %f\n", param.pitch);
	}
	break;
	case MPG123_VERBOSE_KEY:
		param.verbose++;
		if(param.verbose > VERBOSE_MAX)
		{
			param.verbose = 0;
			clear_stat();
		}
		mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0);
	break;
	case MPG123_RVA_KEY:
		if(++param.rva > MPG123_RVA_MAX) param.rva = 0;
		if(param.verbose)
			fprintf(stderr, "\n");
		mpg123_param(fr, MPG123_RVA, param.rva, 0);
		mpg123_volume_change(fr, 0.);
	break;
	case MPG123_PREV_KEY:
		out123_pause(ao);
		out123_drop(ao);

		prev_track();
	break;
	case MPG123_PREV_DIR_KEY:
		out123_pause(ao);
		out123_drop(ao);
		prev_dir();
	break;
	case MPG123_PLAYLIST_KEY:
		fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : "");
		print_playlist(stderr, 1);
		fprintf(stderr, "\n");
	break;
	case MPG123_TAG_KEY:
		fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
		print_id3_tag(fr, param.long_id3, stderr);
		fprintf(stderr, "\n");
	break;
	case MPG123_MPEG_KEY:
		if(param.verbose) print_stat(fr,0,ao); /* Make sure that we are talking about the correct frame. */
		fprintf(stderr, "\n");
		if(param.verbose > 1)
			print_header(fr);
		else
			print_header_compact(fr);
		fprintf(stderr, "\n");
	break;
	case MPG123_HELP_KEY:
	{ /* This is more than the one-liner before, but it's less spaghetti. */
		int i;
		fprintf(stderr,"\n\n -= terminal control keys =-\n");
		for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i)
		{
			if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2);
			else fprintf(stderr, "[%c]", term_help[i].key);

			fprintf(stderr, "\t%s\n", term_help[i].desc);
		}
		fprintf(stderr, "\nAlso, the number row (starting at 1, ending at 0) gives you jump points into the current track at 10%% intervals.\n");
		fprintf(stderr, "\n");
	}
	break;
	case MPG123_FRAME_INDEX_KEY:
	case MPG123_VARIOUS_INFO_KEY:
		if(param.verbose) fprintf(stderr, "\n");
		switch(val) /* because of tolower() ... */
		{
			case MPG123_FRAME_INDEX_KEY:
			print_index(fr);
			{
				long accurate;
				if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK)
				fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes"));
				else
				error1("Unable to get state: %s", mpg123_strerror(fr));
			}
			break;
			case MPG123_VARIOUS_INFO_KEY:
			{
				const char* curdec = mpg123_current_decoder(fr);
				if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n");
				else fprintf(stderr, "Active decoder: %s\n", curdec);
			}
		}
	break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	{
		off_t len;
		int num;
		num = val == '0' ? 10 : val - '0';
		--num; /* from 0 to 9 */

		/* Do not swith to seekmode() here, as we are jumping once to a
		   specific position. Dropping buffer contents is enough and there
		   is no race filling the buffer or waiting for more incremental
		   seek orders. */
		len = mpg123_length(fr);
		out123_pause(ao);
		out123_drop(ao);
		if(len > 0)
			mpg123_seek(fr, (off_t)( (num/10.)*len ), SEEK_SET);
	}
	break;
	case MPG123_BOOKMARK_KEY:
		continue_msg("BOOKMARK");
	break;
	default:
		;
	}
}
Пример #10
0
int PlayMusic()
{
	char buff[MAX_PATH] = {0};
	DWORD ret;
	long rate;
	int channels;
	WAVEFORMATEX wfx;
	DWORD i;
	int readBytes;
	MMRESULT result;
	
	if(pauseFlag == TRUE && lastFrame == 0)
	{
		goto CONTINUE;
	}

	_snprintf(buff, MAX_PATH, "%s\\\\%s", dir, fileInfo.cFileName);
	ret = mpg123_open(mh, buff);
	if(ret != MPG123_OK)
	{
		return 1;
	}
	
	ret = mpg123_getformat(mh, &rate, &channels, NULL);
	if(ret != MPG123_OK)
	{
		return 2;
	}

	ZeroMemory(&wfx, sizeof(wfx));
	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.nChannels = channels;
	wfx.nSamplesPerSec = rate;
	wfx.wBitsPerSample = 16;
	wfx.cbSize = 0;
	wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
	wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * wfx.wBitsPerSample / 8;

	if(lastFrame != 0)
	{
		mpg123_seek_frame(mh, lastFrame, SEEK_SET);
		lastFrame = 0;
	}

	ret = waveOutOpen(&waveOut, -1, &wfx, WaveOutProc, NULL, CALLBACK_FUNCTION);
	if(ret != MMSYSERR_NOERROR)
	{
		return 3;
	}

CONTINUE:
	for(i = 0; i < HEAD_NUM; i++)
	{
		ret = mpg123_read(mh, p[i], SOUND_BUFFER_LEN, &readBytes);
		if(ret != MPG123_OK)
		{
			return 4;
		}

		ZeroMemory(pHeader[i], sizeof(WAVEHDR));
		pHeader[i]->dwBufferLength = readBytes;
		pHeader[i]->lpData = p[i];

		result = waveOutPrepareHeader(waveOut, pHeader[i], sizeof(WAVEHDR));
		if(result != MMSYSERR_NOERROR)
		{
			return 5;
		}

		result = waveOutWrite(waveOut, pHeader[i], sizeof(WAVEHDR));
		if(result != MMSYSERR_NOERROR)
		{
			return 6;
		}
	}

	playingFlag = TRUE;
	stopFlag = FALSE;
	pauseFlag = FALSE;
	return 0;
}
Пример #11
0
static void term_handle_input(mpg123_handle *fr, audio_output_t *ao, int do_delay)
{
  int n = 1;
  /* long offset = 0; */
  
  while(n > 0) {
    fd_set r;
    struct timeval t;
    char val;

    t.tv_sec=0;
    t.tv_usec=(do_delay) ? 10*1000 : 0;
    
    FD_ZERO(&r);
    FD_SET(0,&r);
    n = select(1,&r,NULL,NULL,&t);
    if(n > 0 && FD_ISSET(0,&r)) {
      if(read(0,&val,1) <= 0)
        break;

      switch(tolower(val)) {
	case MPG123_BACK_KEY:
        if(!param.usebuffer) ao->flush(ao);
				else buffer_resync();
		if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));

		if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0)
		error1("Seek to begin failed: %s", mpg123_strerror(fr));

		framenum=0;
		break;
	case MPG123_NEXT_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */
	  next_track();
	  break;
	case MPG123_QUIT_KEY:
		debug("QUIT");
		if(stopped)
		{
			stopped = 0;
			if(param.usebuffer)
			{
				buffer_resync();
				buffer_start();
			}
		}
		set_intflag();
		offset = 0;
	  break;
	case MPG123_PAUSE_KEY:
  	  paused=1-paused;
	  if(paused) {
			/* Not really sure if that is what is wanted
			   This jumps in audio output, but has direct reaction to pausing loop. */
			if(param.usebuffer) buffer_resync();

			pause_recycle(fr);
	  }
		if(stopped)
		{
			stopped=0;
			if(param.usebuffer) buffer_start();
		}
	  fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_STOP_KEY:
	case ' ':
		/* when seeking while stopped and then resuming, I want to prevent the chirp from the past */
		if(!param.usebuffer) ao->flush(ao);
	  stopped=1-stopped;
	  if(paused) {
		  paused=0;
		  offset -= pause_cycle;
	  }
		if(param.usebuffer)
		{
			if(stopped) buffer_stop();
			else
			{
				/* When we stopped buffer for seeking, we must resync. */
				if(offset) buffer_resync();

				buffer_start();
			}
		}
	  fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_FINE_REWIND_KEY:
	  if(param.usebuffer) seekmode();
	  offset--;
	  break;
	case MPG123_FINE_FORWARD_KEY:
	  seekmode();
	  offset++;
	  break;
	case MPG123_REWIND_KEY:
	  seekmode();
  	  offset-=10;
	  break;
	case MPG123_FORWARD_KEY:
	  seekmode();
	  offset+=10;
	  break;
	case MPG123_FAST_REWIND_KEY:
	  seekmode();
	  offset-=50;
	  break;
	case MPG123_FAST_FORWARD_KEY:
	  seekmode();
	  offset+=50;
	  break;
	case MPG123_VOL_UP_KEY:
		mpg123_volume_change(fr, 0.02);
	break;
	case MPG123_VOL_DOWN_KEY:
		mpg123_volume_change(fr, -0.02);
	break;
	case MPG123_PITCH_UP_KEY:
	case MPG123_PITCH_BUP_KEY:
	case MPG123_PITCH_DOWN_KEY:
	case MPG123_PITCH_BDOWN_KEY:
	case MPG123_PITCH_ZERO_KEY:
	{
		double new_pitch = param.pitch;
		switch(val) /* Not tolower here! */
		{
			case MPG123_PITCH_UP_KEY:    new_pitch += MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BUP_KEY:   new_pitch += MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_DOWN_KEY:  new_pitch -= MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_ZERO_KEY:  new_pitch = 0.0; break;
		}
		set_pitch(fr, ao, new_pitch);
		fprintf(stderr, "New pitch: %f\n", param.pitch);
	}
	break;
	case MPG123_VERBOSE_KEY:
		param.verbose++;
		if(param.verbose > VERBOSE_MAX)
		{
			param.verbose = 0;
			clear_stat();
		}
		mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0);
	break;
	case MPG123_RVA_KEY:
		if(++param.rva > MPG123_RVA_MAX) param.rva = 0;
		mpg123_param(fr, MPG123_RVA, param.rva, 0);
		mpg123_volume_change(fr, 0.);
	break;
	case MPG123_PREV_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */

		prev_track();
	break;
	case MPG123_PLAYLIST_KEY:
		fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : "");
		print_playlist(stderr, 1);
		fprintf(stderr, "\n");
	break;
	case MPG123_TAG_KEY:
		fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
		print_id3_tag(fr, param.long_id3, stderr);
		fprintf(stderr, "\n");
	break;
	case MPG123_MPEG_KEY:
		if(param.verbose) print_stat(fr,0,0); /* Make sure that we are talking about the correct frame. */
		fprintf(stderr, "\n");
		print_header(fr);
		fprintf(stderr, "\n");
	break;
	case MPG123_HELP_KEY:
	{ /* This is more than the one-liner before, but it's less spaghetti. */
		int i;
		fprintf(stderr,"\n\n -= terminal control keys =-\n");
		for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i)
		{
			if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2);
			else fprintf(stderr, "[%c]", term_help[i].key);

			fprintf(stderr, "\t%s\n", term_help[i].desc);
		}
		fprintf(stderr, "\n");
	}
	break;
	case MPG123_FRAME_INDEX_KEY:
	case MPG123_VARIOUS_INFO_KEY:
		if(param.verbose) fprintf(stderr, "\n");
		switch(val) /* because of tolower() ... */
		{
			case MPG123_FRAME_INDEX_KEY:
			print_index(fr);
			{
				long accurate;
				if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK)
				fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes"));
				else
				error1("Unable to get state: %s", mpg123_strerror(fr));
			}
			break;
			case MPG123_VARIOUS_INFO_KEY:
			{
				const char* curdec = mpg123_current_decoder(fr);
				if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n");
				else fprintf(stderr, "Active decoder: %s\n", curdec);
			}
		}
	break;
	default:
	  ;
      }
    }
  }
}
Пример #12
0
int control_generic (mpg123_handle *fr)
{
    struct timeval tv;
    fd_set fds;
    int n;

    /* ThOr */
    char alive = 1;
    char silent = 0;

    /* responses to stderr for frontends needing audio data from stdout */
    if (param.remote_err)
        outstream = stderr;
    else
        outstream = stdout;

#ifndef WIN32
    setlinebuf(outstream);
#else /* perhaps just use setvbuf as it's C89 */
    /*
    fprintf(outstream, "You are on Win32 and want to use the control interface... tough luck: We need a replacement for select on STDIN first.\n");
    return 0;
    setvbuf(outstream, (char*)NULL, _IOLBF, 0);
    */
#endif
    /* the command behaviour is different, so is the ID */
    /* now also with version for command availability */
    fprintf(outstream, "@R MPG123 (ThOr) v8\n");
#ifdef FIFO
    if(param.fifo)
    {
        if(param.fifo[0] == 0)
        {
            error("You wanted an empty FIFO name??");
            return 1;
        }
#ifndef WANT_WIN32_FIFO
        unlink(param.fifo);
        if(mkfifo(param.fifo, 0666) == -1)
        {
            error2("Failed to create FIFO at %s (%s)", param.fifo, strerror(errno));
            return 1;
        }
        debug("going to open named pipe ... blocking until someone gives command");
#endif /* WANT_WIN32_FIFO */
#ifdef WANT_WIN32_FIFO
        control_file = win32_fifo_mkfifo(param.fifo);
#else
        control_file = open(param.fifo,O_RDONLY);
#endif /* WANT_WIN32_FIFO */
        debug("opened");
    }
#endif

    while (alive)
    {
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        FD_ZERO(&fds);
        FD_SET(control_file, &fds);
        /* play frame if no command needs to be processed */
        if (mode == MODE_PLAYING) {
#ifdef WANT_WIN32_FIFO
            n = win32_fifo_read_peek(&tv);
#else
            n = select(32, &fds, NULL, NULL, &tv);
#endif
            if (n == 0) {
                if (!play_frame())
                {
                    /* When the track ended, user may want to keep it open (to seek back),
                       so there is a decision between stopping and pausing at the end. */
                    if(param.keep_open)
                    {
                        mode = MODE_PAUSED;
                        /* Hm, buffer should be stopped already, shouldn't it? */
                        if(param.usebuffer) out123_pause(ao);
                        generic_sendmsg("P 1");
                    }
                    else
                    {
                        mode = MODE_STOPPED;
                        close_track();
                        generic_sendmsg("P 0");
                    }
                    continue;
                }
                if (init) {
                    print_remote_header(fr);
                    init = 0;
                }
                if(silent == 0)
                {
                    generic_sendstat(fr);
                    if(mpg123_meta_check(fr) & MPG123_NEW_ICY)
                    {
                        char *meta;
                        if(mpg123_icy(fr, &meta) == MPG123_OK)
                            generic_sendmsg("I ICY-META: %s", meta != NULL ? meta : "<nil>");
                    }
                }
            }
        }
        else {
            /* wait for command */
            while (1) {
#ifdef WANT_WIN32_FIFO
                n = win32_fifo_read_peek(NULL);
#else
                n = select(32, &fds, NULL, NULL, NULL);
#endif
                if (n > 0)
                    break;
            }
        }

        /*  on error */
        if (n < 0) {
            fprintf(stderr, "Error waiting for command: %s\n", strerror(errno));
            return 1;
        }

        /* read & process commands */
        if (n > 0)
        {
            short int len = 1; /* length of buffer */
            char *cmd, *arg; /* variables for parsing, */
            char *comstr = NULL; /* gcc thinks that this could be used uninitialited... */
            char buf[REMOTE_BUFFER_SIZE];
            short int counter;
            char *next_comstr = buf; /* have it initialized for first command */

            /* read as much as possible, maybe multiple commands */
            /* When there is nothing to read (EOF) or even an error, it is the end */
#ifdef WANT_WIN32_FIFO
            len = win32_fifo_read(buf,REMOTE_BUFFER_SIZE);
#else
            len = read(control_file, buf, REMOTE_BUFFER_SIZE);
#endif
            if(len < 1)
            {
#ifdef FIFO
                if(len == 0 && param.fifo)
                {
                    debug("fifo ended... reopening");
#ifdef WANT_WIN32_FIFO
                    win32_fifo_mkfifo(param.fifo);
#else
                    close(control_file);
                    control_file = open(param.fifo,O_RDONLY|O_NONBLOCK);
#endif
                    if(control_file < 0) {
                        error1("open of fifo failed... %s", strerror(errno));
                        break;
                    }
                    continue;
                }
#endif
                if(len < 0) error1("command read error: %s", strerror(errno));
                break;
            }

            debug1("read %i bytes of commands", len);
            /* one command on a line - separation by \n -> C strings in a row */
            for(counter = 0; counter < len; ++counter)
            {
                /* line end is command end */
                if( (buf[counter] == '\n') || (buf[counter] == '\r') )
                {
                    debug1("line end at counter=%i", counter);
                    buf[counter] = 0; /* now it's a properly ending C string */
                    comstr = next_comstr;

                    /* skip the additional line ender of \r\n or \n\r */
                    if( (counter < (len - 1)) && ((buf[counter+1] == '\n') || (buf[counter+1] == '\r')) ) buf[++counter] = 0;

                    /* next "real" char is first of next command */
                    next_comstr = buf + counter+1;

                    /* directly process the command now */
                    debug1("interpreting command: %s", comstr);
                    if(strlen(comstr) == 0) continue;

                    /* PAUSE */
                    if (!strcasecmp(comstr, "P") || !strcasecmp(comstr, "PAUSE")) {
                        if(mode != MODE_STOPPED)
                        {
                            if (mode == MODE_PLAYING) {
                                mode = MODE_PAUSED;
                                out123_pause(ao);
                                generic_sendmsg("P 1");
                            } else {
                                mode = MODE_PLAYING;
                                out123_continue(ao);
                                generic_sendmsg("P 2");
                            }
                        } else generic_sendmsg("P 0");
                        continue;
                    }

                    /* STOP */
                    if (!strcasecmp(comstr, "S") || !strcasecmp(comstr, "STOP")) {
                        if (mode != MODE_STOPPED) {
                            /* Do we want to drop here? */
                            out123_drop(ao);
                            out123_stop(ao);
                            close_track();
                            mode = MODE_STOPPED;
                            generic_sendmsg("P 0");
                        } else generic_sendmsg("P 0");
                        continue;
                    }

                    /* SILENCE */
                    if(!strcasecmp(comstr, "SILENCE")) {
                        silent = 1;
                        generic_sendmsg("silence");
                        continue;
                    }

                    if(!strcasecmp(comstr, "T") || !strcasecmp(comstr, "TAG")) {
                        generic_sendalltag(fr);
                        continue;
                    }

                    if(!strcasecmp(comstr, "SCAN"))
                    {
                        if(mode != MODE_STOPPED)
                        {
                            if(mpg123_scan(fr) == MPG123_OK)
                                generic_sendmsg("SCAN done");
                            else
                                generic_sendmsg("E %s", mpg123_strerror(fr));
                        }
                        else generic_sendmsg("E No track loaded!");

                        continue;
                    }

                    if(!strcasecmp(comstr, "SAMPLE"))
                    {
                        off_t pos = mpg123_tell(fr);
                        off_t len = mpg123_length(fr);
                        /* I need to have portable printf specifiers that do not truncate the type... more autoconf... */
                        if(len < 0) generic_sendmsg("E %s", mpg123_strerror(fr));
                        else generic_sendmsg("SAMPLE %li %li", (long)pos, (long)len);
                        continue;
                    }

                    if(!strcasecmp(comstr, "FORMAT"))
                    {
                        long rate;
                        int ch;
                        int ret = mpg123_getformat(fr, &rate, &ch, NULL);
                        /* I need to have portable printf specifiers that do not truncate the type... more autoconf... */
                        if(ret < 0) generic_sendmsg("E %s", mpg123_strerror(fr));
                        else generic_sendmsg("FORMAT %li %i", rate, ch);
                        continue;
                    }

                    if(!strcasecmp(comstr, "SHOWEQ"))
                    {
                        int i;
                        generic_sendmsg("SHOWEQ {");
                        for(i=0; i<32; ++i)
                        {
                            generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_LEFT, i, mpg123_geteq(fr, MPG123_LEFT, i));
                            generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_RIGHT, i, mpg123_geteq(fr, MPG123_RIGHT, i));
                        }
                        generic_sendmsg("SHOWEQ }");
                        continue;
                    }

                    if(!strcasecmp(comstr, "STATE"))
                    {
                        long val;
                        generic_sendmsg("STATE {");
                        /* Get some state information bits and display them. */
                        if(mpg123_getstate(fr, MPG123_ACCURATE, &val, NULL) == MPG123_OK)
                            generic_sendmsg("STATE accurate %li", val);

                        generic_sendmsg("STATE }");
                        continue;
                    }

                    /* QUIT */
                    if (!strcasecmp(comstr, "Q") || !strcasecmp(comstr, "QUIT")) {
                        alive = FALSE;
                        continue;
                    }

                    /* some HELP */
                    if (!strcasecmp(comstr, "H") || !strcasecmp(comstr, "HELP")) {
                        generic_sendmsg("H {");
                        generic_sendmsg("H HELP/H: command listing (LONG/SHORT forms), command case insensitve");
                        generic_sendmsg("H LOAD/L <trackname>: load and start playing resource <trackname>");
                        generic_sendmsg("H LOADPAUSED/LP <trackname>: load but do not start playing resource <trackname>");
                        generic_sendmsg("H LOADLIST/LL <entry> <url>: load a playlist from given <url>, and display its entries, optionally load and play one of these specificed by the integer <entry> (<0: just list, 0: play last track, >0:play track with that position in list)");
                        generic_sendmsg("H PAUSE/P: pause playback");
                        generic_sendmsg("H STOP/S: stop playback (closes file)");
                        generic_sendmsg("H JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> or change position by offset, same in seconds if number followed by \"s\"");
                        generic_sendmsg("H VOLUME/V <percent>: set volume in % (0..100...); float value");
                        generic_sendmsg("H RVA off|(mix|radio)|(album|audiophile): set rva mode");
                        generic_sendmsg("H EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel %i (left) or %i (right) or %i (both)", MPG123_LEFT, MPG123_RIGHT, MPG123_LR);
                        generic_sendmsg("H EQFILE <filename>: load EQ settings from a file");
                        generic_sendmsg("H SHOWEQ: show all equalizer settings (as <channel> <band> <value> lines in a SHOWEQ block (like TAG))");
                        generic_sendmsg("H SEEK/K <sample>|<+offset>|<-offset>: jump to output sample position <samples> or change position by offset");
                        generic_sendmsg("H SCAN: scan through the file, building seek index");
                        generic_sendmsg("H SAMPLE: print out the sample position and total number of samples");
                        generic_sendmsg("H FORMAT: print out sampling rate in Hz and channel count");
                        generic_sendmsg("H SEQ <bass> <mid> <treble>: simple eq setting...");
                        generic_sendmsg("H PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 %% faster)");
                        generic_sendmsg("H SILENCE: be silent during playback (meaning silence in text form)");
                        generic_sendmsg("H STATE: Print auxiliary state info in several lines (just try it to see what info is there).");
                        generic_sendmsg("H TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names. NOTE: ID3v2 data will be deleted on non-forward seeks.");
                        generic_sendmsg("H    The output is multiple lines, begin marked by \"@T {\", end by \"@T }\".");
                        generic_sendmsg("H    ID3v1 data is like in the @I info lines (see below), just with \"@T\" in front.");
                        generic_sendmsg("H    An ID3v2 data field is introduced via ([ ... ] means optional):");
                        generic_sendmsg("H     @T ID3v2.<NAME>[ [lang(<LANG>)] desc(<description>)]:");
                        generic_sendmsg("H    The lines of data follow with \"=\" prefixed:");
                        generic_sendmsg("H     @T =<one line of content in UTF-8 encoding>");
                        generic_sendmsg("H meaning of the @S stream info:");
                        generic_sendmsg("H %s", remote_header_help);
                        generic_sendmsg("H The @I lines after loading a track give some ID3 info, the format:");
                        generic_sendmsg("H      @I ID3:artist  album  year  comment genretext");
                        generic_sendmsg("H     where artist,album and comment are exactly 30 characters each, year is 4 characters, genre text unspecified.");
                        generic_sendmsg("H     You will encounter \"@I ID3.genre:<number>\" and \"@I ID3.track:<number>\".");
                        generic_sendmsg("H     Then, there is an excerpt of ID3v2 info in the structure");
                        generic_sendmsg("H      @I ID3v2.title:Blabla bla Bla");
                        generic_sendmsg("H     for every line of the \"title\" data field. Likewise for other fields (author, album, etc).");
                        generic_sendmsg("H }");
                        continue;
                    }

                    /* commands with arguments */
                    cmd = NULL;
                    arg = NULL;
                    cmd = strtok(comstr," \t"); /* get the main command */
                    arg = strtok(NULL,""); /* get the args */

                    if (cmd && strlen(cmd) && arg && strlen(arg))
                    {
#ifndef NO_EQUALIZER
                        /* Simple EQ: SEQ <BASS> <MID> <TREBLE>  */
                        if (!strcasecmp(cmd, "SEQ")) {
                            double b,m,t;
                            int cn;
                            if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3)
                            {
                                /* Consider adding mpg123_seq()... but also, on could define a nicer courve for that. */
                                if ((t >= 0) && (t <= 3))
                                    for(cn=0; cn < 1; ++cn)	mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, b);

                                if ((m >= 0) && (m <= 3))
                                    for(cn=1; cn < 2; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, m);

                                if ((b >= 0) && (b <= 3))
                                    for(cn=2; cn < 32; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, t);

                                generic_sendmsg("bass: %f mid: %f treble: %f", b, m, t);
                            }
                            else generic_sendmsg("E invalid arguments for SEQ: %s", arg);
                            continue;
                        }

                        /* Equalizer control :) (JMG) */
                        if (!strcasecmp(cmd, "E") || !strcasecmp(cmd, "EQ")) {
                            double e; /* ThOr: equalizer is of type real... whatever that is */
                            int c, v;
                            /*generic_sendmsg("%s",updown);*/
                            if(sscanf(arg, "%i %i %lf", &c, &v, &e) == 3)
                            {
                                if(mpg123_eq(fr, c, v, e) == MPG123_OK)
                                    generic_sendmsg("%i : %i : %f", c, v, e);
                                else
                                    generic_sendmsg("E failed to set eq: %s", mpg123_strerror(fr));
                            }
                            else generic_sendmsg("E invalid arguments for EQ: %s", arg);
                            continue;
                        }

                        if(!strcasecmp(cmd, "EQFILE"))
                        {
                            equalfile = arg;
                            if(load_equalizer(fr) == 0)
                                generic_sendmsg("EQFILE done");
                            else
                                generic_sendmsg("E failed to parse given eq file");

                            continue;
                        }
#endif
                        /* SEEK to a sample offset */
                        if(!strcasecmp(cmd, "K") || !strcasecmp(cmd, "SEEK"))
                        {
                            off_t soff;
                            off_t oldpos;
                            off_t newpos;
                            char *spos = arg;
                            int whence = SEEK_SET;
                            if(mode == MODE_STOPPED)
                            {
                                generic_sendmsg("E No track loaded!");
                                continue;
                            }
                            oldpos = mpg123_tell(fr);

                            soff = (off_t) atobigint(spos);
                            if(spos[0] == '-' || spos[0] == '+') whence = SEEK_CUR;
                            if(0 > (soff = mpg123_seek(fr, soff, whence)))
                            {
                                generic_sendmsg("E Error while seeking: %s", mpg123_strerror(fr));
                                mpg123_seek(fr, 0, SEEK_SET);
                            }
                            out123_drop(ao);

                            newpos = mpg123_tell(fr);
                            if(newpos <= oldpos) mpg123_meta_free(fr);

                            generic_sendmsg("K %"OFF_P, (off_p)newpos);
                            continue;
                        }
                        /* JUMP */
                        if (!strcasecmp(cmd, "J") || !strcasecmp(cmd, "JUMP")) {
                            char *spos;
                            off_t offset;
                            off_t oldpos;
                            double secs;

                            spos = arg;
                            if(mode == MODE_STOPPED)
                            {
                                generic_sendmsg("E No track loaded!");
                                continue;
                            }
                            oldpos = framenum;

                            if(spos[strlen(spos)-1] == 's' && sscanf(arg, "%lf", &secs) == 1) offset = mpg123_timeframe(fr, secs);
                            else offset = atol(spos);
                            /* totally replaced that stuff - it never fully worked
                               a bit usure about why +pos -> spos+1 earlier... */
                            if (spos[0] == '-' || spos[0] == '+') offset += framenum;

                            if(0 > (framenum = mpg123_seek_frame(fr, offset, SEEK_SET)))
                            {
                                generic_sendmsg("E Error while seeking");
                                mpg123_seek_frame(fr, 0, SEEK_SET);
                            }
                            out123_drop(ao);

                            if(framenum <= oldpos) mpg123_meta_free(fr);
                            generic_sendmsg("J %d", framenum);
                            continue;
                        }

                        /* VOLUME in percent */
                        if(!strcasecmp(cmd, "V") || !strcasecmp(cmd, "VOLUME"))
                        {
                            double v;
                            mpg123_volume(fr, atof(arg)/100);
                            mpg123_getvolume(fr, &v, NULL, NULL); /* Necessary? */
                            generic_sendmsg("V %f%%", v * 100);
                            continue;
                        }

                        /* PITCH (playback speed) in percent */
                        if(!strcasecmp(cmd, "PITCH"))
                        {
                            double p;
                            if(sscanf(arg, "%lf", &p) == 1)
                            {
                                set_pitch(fr, ao, p);
                                generic_sendmsg("PITCH %f", param.pitch);
                            }
                            else generic_sendmsg("E invalid arguments for PITCH: %s", arg);
                            continue;
                        }

                        /* RVA mode */
                        if(!strcasecmp(cmd, "RVA"))
                        {
                            if(!strcasecmp(arg, "off")) param.rva = MPG123_RVA_OFF;
                            else if(!strcasecmp(arg, "mix") || !strcasecmp(arg, "radio")) param.rva = MPG123_RVA_MIX;
                            else if(!strcasecmp(arg, "album") || !strcasecmp(arg, "audiophile")) param.rva = MPG123_RVA_ALBUM;
                            mpg123_volume_change(fr, 0.);
                            generic_sendmsg("RVA %s", rva_name[param.rva]);
                            continue;
                        }

                        /* LOAD - actually play */
                        if (!strcasecmp(cmd, "L") || !strcasecmp(cmd, "LOAD")) {
                            generic_load(fr, arg, MODE_PLAYING);
                            continue;
                        }

                        if (!strcasecmp(cmd, "LL") || !strcasecmp(cmd, "LOADLIST")) {
                            generic_loadlist(fr, arg);
                            continue;
                        }

                        /* LOADPAUSED */
                        if (!strcasecmp(cmd, "LP") || !strcasecmp(cmd, "LOADPAUSED")) {
                            generic_load(fr, arg, MODE_PAUSED);
                            continue;
                        }

                        /* no command matched */
                        generic_sendmsg("E Unknown command: %s", cmd); /* unknown command */
                    } /* end commands with arguments */
                    else generic_sendmsg("E Unknown command or no arguments: %s", comstr); /* unknown command */

                } /* end of single command processing */
            } /* end of scanning the command buffer */

            /*
               when last command had no \n... should I discard it?
               Ideally, I should remember the part and wait for next
            	 read() to get the rest up to a \n. But that can go
            	 to infinity. Too long commands too quickly are just
            	 bad. Cannot/Won't change that. So, discard the unfinished
            	 command and have fingers crossed that the rest of this
            	 unfinished one qualifies as "unknown".
            */
            if(buf[len-1] != 0)
            {
                char lasti = buf[len-1];
                buf[len-1] = 0;
                generic_sendmsg("E Unfinished command: %s%c", comstr, lasti);
            }
        } /* end command reading & processing */
    } /* end main (alive) loop */
    debug("going to end");
    /* quit gracefully */
    debug("closing control");
#ifdef FIFO
#if WANT_WIN32_FIFO
    win32_fifo_close();
#else
    close(control_file); /* be it FIFO or STDIN */
    if(param.fifo) unlink(param.fifo);
#endif /* WANT_WIN32_FIFO */
#endif
    debug("control_generic returning");
    return 0;
}
Пример #13
0
int DealMsg(char *buff, int len)
{
	if(strcmp(buff, "next") == 0)
	{
		StopMusic();
		stopFlag = TRUE;
		pauseFlag = FALSE;
		if(GetNextFile() != 0 ||
			PlayMusic() != 0)
		{
			return 1;
		}
	}
	else if(strcmp(buff, "again") == 0)
	{
		StopMusic();
		stopFlag = TRUE;
		pauseFlag = FALSE;
		if(PlayMusic() != 0)
		{
			return 1;
		}
	}
	else if(strcmp(buff, "list") == 0)
	{
		WIN32_FIND_DATA tmpFileInfo;
		HANDLE tmpHFile;
		char tmpBuff[10240] = {0};
		int i = 0;

		tmpHFile = FindFirstFile(glob_file, &tmpFileInfo);
		if(tmpHFile == INVALID_HANDLE_VALUE)
		{
			return 1;
		}

		do 
		{
			strcat(tmpBuff, tmpFileInfo.cFileName);
			strcat(tmpBuff, "\n");
		} while (FindNextFile(tmpHFile, &tmpFileInfo));

		send(client, tmpBuff, strlen(tmpBuff), 0);
		CloseHandle(tmpHFile);
	}
	else if(strcmp(buff, "current") == 0)
	{
		int ret;
		double second;
		double second_left;
		char currentBuffer[256] = {0};
		char *p;

		if (stopFlag == TRUE)
		{
			p = "stop";
		}
		else if(pauseFlag == TRUE)
		{
			p = "pause";
		}
		else 
		{
			p = "play";
		}

		ret = mpg123_position(mh, NULL, NULL, NULL, NULL, &second, &second_left);
		if(ret != MPG123_OK)
		{
			return 1;
		}

		_snprintf(currentBuffer, sizeof(currentBuffer), "%s %s %lf %lf", p, fileInfo.cFileName, second, second_left);
		send(client, currentBuffer, strlen(currentBuffer), 0);
	}
	else if(strncmp(buff, "seek ", 5) == 0)
	{
		double secondToSet;
		off_t currentFrame;
		off_t frameLeft;
		double currentSecond;
		double secondLeft;
		int ret;
		double totalSecond;
		off_t totalFrame;
		off_t frameToSet;

		if(buff[5] < '1' || buff[5] > '9')
		{
			return 0;
		}

		secondToSet = atof((const char *)&buff[5]);
		frameToSet = mpg123_timeframe(mh, secondToSet);
		if(frameToSet < 0)
		{
			return 1;
		}
		EnterCriticalSection(&cs);
		ret = mpg123_seek_frame(mh, frameToSet, SEEK_SET);
		LeaveCriticalSection(&cs);
		if(ret < 0)
		{
			return 1;
		}
	}
	else if(strncmp(buff, "select ", 7) == 0)
	{
		char path[MAX_PATH] = {0};
		strcpy(path, dir);
		strcat(path, "\\\\");
		strcat(path, &buff[7]);

		if(!PathFileExists(path))
		{
			return 0;
		}

		StopMusic();
		stopFlag = TRUE;
		pauseFlag = FALSE;
		while(strcmp(fileInfo.cFileName, &buff[7]) != 0)
		{
			GetNextFile();
		}
		if(PlayMusic() != 0)
		{
			return 1;
		}
	}
	else if(strcmp(buff, "stop") == 0)
	{
		if(pauseFlag == FALSE)
		{
			StopMusic();
			mpg123_seek_frame(mh, 0, SEEK_SET);
			stopFlag = TRUE;
		}
	}
	else if(strcmp(buff, "play") == 0)
	{
		if(playingFlag == FALSE)
			PlayMusic();
	}
	else if(strcmp(buff, "pause") == 0)
	{
		if (stopFlag == FALSE)
		{
			playingFlag = FALSE;
			pauseFlag = TRUE;
		}
	}

	return 0;
}
Пример #14
0
VALUE rb_mpg123_seek_frame(VALUE self, VALUE offset)
{
  return INT2FIX(mpg123_seek_frame(DATA_PTR(self), FIX2INT(offset), SEEK_SET));
}
Пример #15
0
void* player_thread(void* _mp3_info) 
{
  log_debug("player thread started");
  
  mp3_t* mp3_info = (mp3_t* ) _mp3_info;
  long current_position_in_ms = 0;
  long previous_position_in_ms = -1; 
  long guard_position_in_ms = -1;
  el_bool playing = el_false;
  pthread_t thread_id;
  int no_count = 0;
  
  post_event(mp3_info->client_notification, AUDIO_READY, current_position_in_ms);
 
  audio_event_t *event;
  event = audio_event_fifo_dequeue(mp3_info->player_control);
  while (event->state != INTERNAL_CMD_DESTROY) {
    
    if (event->state != INTERNAL_CMD_NONE) {
      log_debug4("event = %s, %ld, %s", audio_event_name(event->state), event->position_in_ms, mp3_info->file_or_url);
    }
    
    audio_state_t event_state = event->state;
    long event_position = event->position_in_ms;
    audio_event_destroy(event);
    
    switch (event_state) {
      case INTERNAL_CMD_LOAD_FILE: {
        playing = el_false;
        
        // Stop stream, if playing
        if (!mp3_info->is_file) {
          mp3_info->continue_streaming = el_false;
          psem_wait(mp3_info->stream_ready);
        }
        
        if (mp3_info->is_open) {
          mpg123_close(mp3_info->handle);
          aodev_close(mp3_info->ao_handle);
        }
        mpg123_open(mp3_info->handle, mp3_info->file_or_url);
        mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding);
        mp3_info->buffer_size = mpg123_outblock(mp3_info->handle);
        mc_free(mp3_info->buffer);
        mp3_info->buffer = mc_malloc(mp3_info->buffer_size * sizeof(char) );
        int bytes_per_sample = get_encsize(mp3_info->encoding);
        aodev_set_format(mp3_info->ao_handle, bytes_per_sample * 8, mp3_info->rate, mp3_info->channels);
        aodev_open(mp3_info->ao_handle);
        mp3_info->is_open = el_true;
        mp3_info->is_file = el_true;
        mp3_info->can_seek = el_true;
        current_position_in_ms = 0;
        guard_position_in_ms = -1; 
        {
          off_t l = mpg123_length(mp3_info->handle);
          if (l == MPG123_ERR) {
            mp3_info->length = -1; 
          } else {
            mp3_info->length = (l * 1000) / mp3_info->rate;
          }
          psem_post(mp3_info->length_set);
        }
      }
      break;
      case INTERNAL_CMD_LOAD_URL: {
        playing = el_false;
        log_debug2("loading url %s", mp3_info->file_or_url);
        // Wait for feeding streams to end
        if (!mp3_info->is_file) {
          mp3_info->continue_streaming = el_false;
          psem_wait(mp3_info->stream_ready);
        }
        mp3_info->is_file = el_false;
        log_debug("current stream ended");
        
        if (mp3_info->is_open) {
          mpg123_close(mp3_info->handle);
          aodev_close(mp3_info->ao_handle);
          mp3_info->is_open = el_false;
        }
        log_debug("aodev closed");
        
        mpg123_open_feed(mp3_info->handle);
        log_debug("feed opened");
        
        pthread_create(&thread_id, NULL, stream_thread, mp3_info);
        log_debug("stream thread started");
        
        mp3_info->is_open = el_true;
        mp3_info->can_seek = el_false;
        current_position_in_ms = 0;
        guard_position_in_ms = -1;
        mp3_info->length = 0;
        mp3_info->continue_streaming = el_true;
        
        psem_post(mp3_info->length_set);
      }
      break;
      case INTERNAL_CMD_SEEK: {
        off_t pos = mpg123_timeframe(mp3_info->handle, (event_position / 1000.0));
        mpg123_seek_frame(mp3_info->handle, pos, SEEK_SET);
      }
      break;
      case INTERNAL_CMD_PLAY: {
        playing = el_true;
      }
      break;
      case INTERNAL_CMD_PAUSE: {
        playing = el_false;
      }
      break;
      case INTERNAL_CMD_GUARD: {
        guard_position_in_ms = event_position;
      }
      break;
      case INTERNAL_CMD_SET_VOLUME: {
        double volume = ((double) event_position) / 1000.0;
        mpg123_volume(mp3_info->handle, volume);
      }
      case INTERNAL_CMD_NONE:
      break;
      default:
      break;
    }
    
    //log_debug3("guard = %d, playing = %d", guard_position_in_ms, playing);
    if (guard_position_in_ms >= 0 && current_position_in_ms >= guard_position_in_ms) {

      guard_position_in_ms = -1;
      post_event(mp3_info->client_notification, AUDIO_GUARD_REACHED, current_position_in_ms);
      
    } else if (playing) {

      if (mp3_info->is_file) {  
        size_t bytes;
        int res = mpg123_read(mp3_info->handle, mp3_info->buffer, mp3_info->buffer_size, &bytes);
        if (res == MPG123_OK) {
          aodev_play_buffer(mp3_info->ao_handle, mp3_info->buffer, bytes);
          off_t frame = mpg123_tellframe(mp3_info->handle);
          double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0);
          //static int prt = 1;
          //if (prt) { printf("tpf=%.6lf\n",time_per_frame);prt=0; }
          current_position_in_ms = (long) (frame * time_per_frame);    // 1 frame is about 26 milliseconds
          if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms;
          if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) {
            post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms);
          }
          previous_position_in_ms = current_position_in_ms;
        } else if (res == MPG123_DONE) {
          post_event(mp3_info->client_notification, AUDIO_EOS, current_position_in_ms);
          playing = el_false;
        } else {
          post_event(mp3_info->client_notification, AUDIO_STATE_ERROR, current_position_in_ms);
          playing = el_false;
        }
      } else { // Stream playing
        
        if (mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) {
          el_bool go_on = el_true; 
          while (go_on && mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) {
            memblock_t* blk = mp3_stream_fifo_dequeue(mp3_info->stream_fifo);
            
            mpg123_feed(mp3_info->handle, (const unsigned char*) memblock_as_str(blk), memblock_size(blk));
            memblock_destroy(blk);
            
            size_t done;
            int err;
            unsigned char *audio;
            off_t frame_offset;
            
            do {
              err = mpg123_decode_frame(mp3_info->handle, &frame_offset, &audio, &done);
              switch(err) {
                case MPG123_NEW_FORMAT:
                  mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding);
                  if (aodev_is_open(mp3_info->ao_handle)) {
                    aodev_close(mp3_info->ao_handle);
                  }
                  aodev_set_format(mp3_info->ao_handle, get_encsize(mp3_info->encoding) * 8, mp3_info->rate, mp3_info->channels);
                  aodev_open(mp3_info->ao_handle);
                break;
                case MPG123_OK:
                  //log_debug2("playing buffer %d", done);
                  aodev_play_buffer(mp3_info->ao_handle, audio, done);
                  off_t frame = mpg123_tellframe(mp3_info->handle);
                  double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0);
                  current_position_in_ms = (long) (frame * time_per_frame);    // 1 frame is about 26 milliseconds
                  if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms;
                  if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) {
                    post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms);
                  }
                  previous_position_in_ms = current_position_in_ms;
                  go_on = el_false;
                  break;
                case MPG123_NEED_MORE:
                  break;
                default:
                  break;
              }
            } while (done > 0);
          }
        } else {
          // no streaming data, prevent race conditions
          // sleep for a small time (50 ms);
          no_count += 1;
          if (no_count > 10) { 
            post_event(mp3_info->client_notification, AUDIO_BUFFERING, current_position_in_ms);
          }
          sleep_ms(50);
        }
      } 
    }
    
    if (playing) {
      if (audio_event_fifo_peek(mp3_info->player_control) != NULL) {
        event = audio_event_fifo_dequeue(mp3_info->player_control);
      } else {
        event = (audio_event_t*) mc_malloc(sizeof(audio_event_t));
        event->state = INTERNAL_CMD_NONE;
        event->position_in_ms = -1;
      }
    } else {
      //log_debug("waiting for next event");
      event = audio_event_fifo_dequeue(mp3_info->player_control);
    }
  }

  // destroy event received
  log_debug("destroy event received");
  
  // Kill playing streams
  if (mp3_info->streaming) {
    mp3_info->continue_streaming = el_false;
    psem_wait(mp3_info->stream_ready);
  }
  
  audio_event_destroy(event);

  // exit thread  
  return NULL;
}
Пример #16
0
int main(int sys_argc, char ** sys_argv)
{
	int result;
	char end_of_files = FALSE;
	long parr;
	char *fname;
	int libpar = 0;
	mpg123_pars *mp;
#if !defined(WIN32) && !defined(GENERIC)
	struct timeval start_time;
#endif
	aux_out = stdout; /* Need to initialize here because stdout is not a constant?! */
#if defined (WANT_WIN32_UNICODE)
	if(win32_cmdline_utf8(&argc, &argv) != 0)
	{
		error("Cannot convert command line to UTF8!");
		safe_exit(76);
	}
#else
	argv = sys_argv;
	argc = sys_argc;
#endif
#if defined (WANT_WIN32_SOCKETS)
	win32_net_init();
#endif

	/* Extract binary and path, take stuff before/after last / or \ . */
	if((prgName = strrchr(argv[0], '/')) || (prgName = strrchr(argv[0], '\\')))
	{
		/* There is some explicit path. */
		prgName[0] = 0; /* End byte for path. */
		prgName++;
		binpath = argv[0];
	}
	else
	{
		prgName = argv[0]; /* No path separators there. */
		binpath = NULL; /* No path at all. */
	}

	/* Need to initialize mpg123 lib here for default parameter values. */

	result = mpg123_init();
	if(result != MPG123_OK)
	{
		error1("Cannot initialize mpg123 library: %s", mpg123_plain_strerror(result));
		safe_exit(77);
	}
	cleanup_mpg123 = TRUE;

	mp = mpg123_new_pars(&result); /* This may get leaked on premature exit(), which is mainly a cosmetic issue... */
	if(mp == NULL)
	{
		error1("Crap! Cannot get mpg123 parameters: %s", mpg123_plain_strerror(result));
		safe_exit(78);
	}

	/* get default values */
	mpg123_getpar(mp, MPG123_DOWN_SAMPLE, &parr, NULL);
	param.down_sample = (int) parr;
	mpg123_getpar(mp, MPG123_RVA, &param.rva, NULL);
	mpg123_getpar(mp, MPG123_DOWNSPEED, &param.halfspeed, NULL);
	mpg123_getpar(mp, MPG123_UPSPEED, &param.doublespeed, NULL);
	mpg123_getpar(mp, MPG123_OUTSCALE, &param.outscale, NULL);
	mpg123_getpar(mp, MPG123_FLAGS, &parr, NULL);
	mpg123_getpar(mp, MPG123_INDEX_SIZE, &param.index_size, NULL);
	param.flags = (int) parr;
	param.flags |= MPG123_SEEKBUFFER; /* Default on, for HTTP streams. */
	mpg123_getpar(mp, MPG123_RESYNC_LIMIT, &param.resync_limit, NULL);
	mpg123_getpar(mp, MPG123_PREFRAMES, &param.preframes, NULL);

#ifdef OS2
        _wildcard(&argc,&argv);
#endif

	while ((result = getlopt(argc, argv, opts)))
	switch (result) {
		case GLO_UNKNOWN:
			fprintf (stderr, "%s: Unknown option \"%s\".\n", 
				prgName, loptarg);
			usage(1);
		case GLO_NOARG:
			fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
				prgName, loptarg);
			usage(1);
	}
	/* Do this _after_ parameter parsing. */
	check_locale(); /* Check/set locale; store if it uses UTF-8. */

	if(param.list_cpu)
	{
		const char **all_dec = mpg123_decoders();
		printf("Builtin decoders:");
		while(*all_dec != NULL){ printf(" %s", *all_dec); ++all_dec; }
		printf("\n");
		mpg123_delete_pars(mp);
		return 0;
	}
	if(param.test_cpu)
	{
		const char **all_dec = mpg123_supported_decoders();
		printf("Supported decoders:");
		while(*all_dec != NULL){ printf(" %s", *all_dec); ++all_dec; }
		printf("\n");
		mpg123_delete_pars(mp);
		return 0;
	}
	if(param.gain != -1)
	{
	    warning("The parameter -g is deprecated and may be removed in the future.");
	}

	if (loptind >= argc && !param.listname && !param.remote) usage(1);
	/* Init audio as early as possible.
	   If there is the buffer process to be spawned, it shouldn't carry the mpg123_handle with it. */
	bufferblock = mpg123_safe_buffer(); /* Can call that before mpg123_init(), it's stateless. */
	if(init_output(&ao) < 0)
	{
		error("Failed to initialize output, goodbye.");
		mpg123_delete_pars(mp);
		return 99; /* It's safe here... nothing nasty happened yet. */
	}
	have_output = TRUE;

	/* ========================================================================================================= */
	/* Enterning the leaking zone... we start messing with stuff here that should be taken care of when leaving. */
	/* Don't just exit() or return out...                                                                        */
	/* ========================================================================================================= */

	httpdata_init(&htd);

#if !defined(WIN32) && !defined(GENERIC)
	if (param.remote)
	{
		param.verbose = 0;
		param.quiet = 1;
		param.flags |= MPG123_QUIET;
	}
#endif

	/* Set the frame parameters from command line options */
	if(param.quiet) param.flags |= MPG123_QUIET;

#ifdef OPT_3DNOW
	if(dnow != 0) param.cpu = (dnow == SET_3DNOW) ? "3dnow" : "i586";
#endif
	if(param.cpu != NULL && (!strcmp(param.cpu, "auto") || !strcmp(param.cpu, ""))) param.cpu = NULL;
	if(!(  MPG123_OK == (result = mpg123_par(mp, MPG123_VERBOSE, param.verbose, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_FLAGS, param.flags, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_DOWN_SAMPLE, param.down_sample, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_RVA, param.rva, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_FORCE_RATE, param.force_rate, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_DOWNSPEED, param.halfspeed, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_UPSPEED, param.doublespeed, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_ICY_INTERVAL, 0, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_RESYNC_LIMIT, param.resync_limit, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_TIMEOUT, param.timeout, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_OUTSCALE, param.outscale, 0))
	    && ++libpar
	    && MPG123_OK == (result = mpg123_par(mp, MPG123_PREFRAMES, param.preframes, 0))
			))
	{
		error2("Cannot set library parameter %i: %s", libpar, mpg123_plain_strerror(result));
		safe_exit(45);
	}
	if (!(param.listentry < 0) && !param.quiet) print_title(stderr); /* do not pollute stdout! */

	{
		long default_index;
		mpg123_getpar(mp, MPG123_INDEX_SIZE, &default_index, NULL);
		if( param.index_size != default_index && (result = mpg123_par(mp, MPG123_INDEX_SIZE, param.index_size, 0.)) != MPG123_OK )
		error1("Setting of frame index size failed: %s", mpg123_plain_strerror(result));
	}

	if(param.force_rate && param.down_sample)
	{
		error("Down sampling and fixed rate options not allowed together!");
		safe_exit(1);
	}

	/* Now actually get an mpg123_handle. */
	mh = mpg123_parnew(mp, param.cpu, &result);
	if(mh == NULL)
	{
		error1("Crap! Cannot get a mpg123 handle: %s", mpg123_plain_strerror(result));
		safe_exit(77);
	}
	mpg123_delete_pars(mp); /* Don't need the parameters anymore ,they're in the handle now. */

	/* Prepare stream dumping, possibly replacing mpg123 reader. */
	if(dump_open(mh) != 0) safe_exit(78);

	/* Now either check caps myself or query buffer for that. */
	audio_capabilities(ao, mh);

	load_equalizer(mh);

#ifdef HAVE_SETPRIORITY
	if(param.aggressive) { /* tst */
		int mypid = getpid();
		setpriority(PRIO_PROCESS,mypid,-20);
	}
#endif

#if defined (HAVE_SCHED_SETSCHEDULER) && !defined (__CYGWIN__) && !defined (HAVE_WINDOWS_H)
/* Cygwin --realtime seems to fail when accessing network, using win32 set priority instead */
/* MinGW may have pthread installed, we prefer win32API */
	if (param.realtime) {  /* Get real-time priority */
	  struct sched_param sp;
	  fprintf(stderr,"Getting real-time priority\n");
	  memset(&sp, 0, sizeof(struct sched_param));
	  sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
	  if (sched_setscheduler(0, SCHED_RR, &sp) == -1)
	    fprintf(stderr,"Can't get real-time priority\n");
	}
#endif

#ifdef HAVE_WINDOWS_H
	/* argument "3" is equivalent to realtime priority class */
	win32_set_priority( param.realtime ? 3 : param.w32_priority);
#endif

	if(!param.remote) prepare_playlist(argc, argv);

#if !defined(WIN32) && !defined(GENERIC)
	/* Remote mode is special... but normal console and terminal-controlled operation needs to catch the SIGINT.
	   For one it serves for track skip when not in terminal control mode.
	   The more important use being a graceful exit, including telling the buffer process what's going on. */
	if(!param.remote) catchsignal (SIGINT, catch_interrupt);
#endif

	if(param.remote) {
		int ret;
		ret = control_generic(mh);
		safe_exit(ret);
	}
#ifdef HAVE_TERMIOS
		debug1("param.term_ctrl: %i", param.term_ctrl);
		if(param.term_ctrl)
			term_init();
#endif
	if(APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number;

	while ((fname = get_next_file()))
	{
		char *dirname, *filename;
		int newdir;
		/* skip_tracks includes the previous one. */
		if(skip_tracks) --skip_tracks;
		if(skip_tracks)
		{
			debug("Skipping this track.");
			continue;
		}
		if(param.delay > 0)
		{
			/* One should enable terminal control during that sleeping phase! */
			if(param.verbose > 2) fprintf(stderr, "Note: pausing %i seconds before next track.\n", param.delay);
			output_pause(ao);
#ifdef WIN32
			Sleep(param.delay*1000);
#else
			sleep(param.delay);
#endif
			output_unpause(ao);
		}
		if(!APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number;

		debug1("Going to play %s", strcmp(fname, "-") ? fname : "standard input");

		if(intflag || !open_track(fname))
		{
#ifdef HAVE_TERMIOS
			/* We need the opportunity to cancel in case of --loop -1 . */
			if(param.term_ctrl) term_control(mh, ao);
#endif
			/* No wait for a second interrupt before we started playing. */
			if(intflag) break;

			continue;
		}

		if(!param.quiet) fprintf(stderr, "\n");
		if(param.index)
		{
			if(param.verbose) fprintf(stderr, "indexing...\r");
			mpg123_scan(mh);
		}
		/*
			Only trigger a seek if we do not want to start with the first frame.
			Rationale: Because of libmpg123 sample accuracy, this could cause an unnecessary backwards seek, that even may fail on non-seekable streams.
			For start frame of 0, we are already at the correct position!
		*/
		framenum = 0;
		if(param.start_frame > 0)
		framenum = mpg123_seek_frame(mh, param.start_frame, SEEK_SET);

		if(APPFLAG(MPG123APP_CONTINUE)) param.start_frame = 0;

		if(framenum < 0)
		{
			error1("Initial seek failed: %s", mpg123_strerror(mh));
			if(mpg123_errcode(mh) == MPG123_BAD_OUTFORMAT)
			{
				fprintf(stderr, "%s", "So, you have trouble getting an output format... this is the matrix of currently possible formats:\n");
				print_capabilities(ao, mh);
				fprintf(stderr, "%s", "Somehow the input data and your choices don't allow one of these.\n");
			}
			mpg123_close(mh);
			continue;
		}

		/* Prinout and xterm title need this, possibly independently. */
		newdir = split_dir_file(fname ? fname : "standard input", &dirname, &filename);

		if (!param.quiet)
		{
			if(newdir) fprintf(stderr, "Directory: %s\n", dirname);

#ifdef HAVE_TERMIOS
		/* Reminder about terminal usage. */
		if(param.term_ctrl) term_hint();
#endif


			fprintf(stderr, "Playing MPEG stream %lu of %lu: %s ...\n", (unsigned long)pl.pos, (unsigned long)pl.fill, filename);
			if(htd.icy_name.fill) fprintf(stderr, "ICY-NAME: %s\n", htd.icy_name.p);
			if(htd.icy_url.fill)  fprintf(stderr, "ICY-URL: %s\n",  htd.icy_url.p);
		}
#if !defined(GENERIC)
{
	const char *term_type;
	term_type = getenv("TERM");
	if(term_type && param.xterm_title)
	{
		if(!strncmp(term_type,"xterm",5) || !strncmp(term_type,"rxvt",4))
		fprintf(stderr, "\033]0;%s\007", filename);
		else if(!strncmp(term_type,"screen",6))
		fprintf(stderr, "\033k%s\033\\", filename);
		else if(!strncmp(term_type,"iris-ansi",9))
		fprintf(stderr, "\033P1.y %s\033\\\033P3.y%s\033\\", filename, filename);

		fflush(stderr); /* Paranoia: will the buffer buffer the escapes? */
	}
}
#endif

/* Rethink that SIGINT logic... */
#if !defined(WIN32) && !defined(GENERIC)
#ifdef HAVE_TERMIOS
		if(!param.term_ctrl)
#endif
			gettimeofday (&start_time, NULL);
#endif

		while(!intflag)
		{
			int meta;
			if(param.frame_number > -1)
			{
				debug1("frames left: %li", (long) frames_left);
				if(!frames_left)
				{
					if(APPFLAG(MPG123APP_CONTINUE)) end_of_files = TRUE;

					break;
				}
			}
			if(!play_frame()) break;
			if(!param.quiet)
			{
				meta = mpg123_meta_check(mh);
				if(meta & (MPG123_NEW_ID3|MPG123_NEW_ICY))
				{
					if(meta & MPG123_NEW_ID3) print_id3_tag(mh, param.long_id3, stderr);
					if(meta & MPG123_NEW_ICY) print_icy(mh, stderr);

					mpg123_meta_free(mh); /* Do not waste memory after delivering. */
				}
			}
			if(!fresh && param.verbose)
			{
#ifndef NOXFERMEM
				if (param.verbose > 1 || !(framenum & 0x7))
					print_stat(mh,0,xfermem_get_usedspace(buffermem)); 
#else
				if(param.verbose > 1 || !(framenum & 0x7))	print_stat(mh,0,0);
#endif
			}
#ifdef HAVE_TERMIOS
			if(!param.term_ctrl) continue;
			else term_control(mh, ao);
#endif
		}

	if(!param.smooth && param.usebuffer) buffer_drain();
	if(param.verbose) print_stat(mh,0,xfermem_get_usedspace(buffermem)); 

	if(!param.quiet)
	{
		double secs;
		long frank;
		fprintf(stderr, "\n");
		if(mpg123_getstate(mh, MPG123_FRANKENSTEIN, &frank, NULL) == MPG123_OK && frank)
		fprintf(stderr, "This was a Frankenstein track.\n");

		mpg123_position(mh, 0, 0, NULL, NULL, &secs, NULL);
		fprintf(stderr,"[%d:%02d] Decoding of %s finished.\n", (int)(secs / 60), ((int)secs) % 60, filename);
	}
	else if(param.verbose) fprintf(stderr, "\n");

	mpg123_close(mh);

	if (intflag)
	{
		if(!skip_or_die(&start_time)) break;

        intflag = FALSE;

#ifndef NOXFERMEM
        if(!param.smooth && param.usebuffer) buffer_resync();
#endif
	}

		if(end_of_files) break;
	} /* end of loop over input files */

	/* Ensure we played everything. */
	if(param.smooth && param.usebuffer)
	{
		buffer_drain();
		buffer_resync();
	}

	if(APPFLAG(MPG123APP_CONTINUE))
	{
		continue_msg("CONTINUE");
	}

	/* Free up memory used by playlist */    
	if(!param.remote) free_playlist();

	safe_exit(0); /* That closes output and restores terminal, too. */
	return 0;
}
Пример #17
0
static cxBool cxMp3StreamSeek(cxAny stream,cxOff off,cxInt flags)
{
    cxMp3Stream this = stream;
    return mpg123_seek_frame(this->mh, off, flags) >= 0;
}