Example #1
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano (updates data structures)
 *	@param piano handle
 *	@param request type
 *	@param waitress handle
 *	@param data pointer (used as request data)
 *	@return 1 on success, 0 otherwise
 */
int BarUiPianoCall (PianoHandle_t *ph, PianoRequestType_t type,
		WaitressHandle_t *waith, void *data, PianoReturn_t *pRet,
		WaitressReturn_t *wRet) {
	PianoRequest_t req;

	memset (&req, 0, sizeof (req));

	/* repeat as long as there are http requests to do */
	do {
		req.data = data;

		*pRet = PianoRequest (ph, &req, type);
		if (*pRet != PIANO_RET_OK) {
			BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
			PianoDestroyRequest (&req);
			return 0;
		}

		*wRet = BarPianoHttpRequest (waith, &req);
		if (*wRet != WAITRESS_RET_OK) {
			BarUiMsg (MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
			PianoDestroyRequest (&req);
			if (req.responseData != NULL) {
				free (req.responseData);
			}
			return 0;
		}

		*pRet = PianoResponse (ph, &req);
		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
			if (*pRet != PIANO_RET_OK) {
				BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
				PianoDestroyRequest (&req);
				if (req.responseData != NULL) {
					free (req.responseData);
				}
				return 0;
			} else {
				BarUiMsg (MSG_NONE, "Ok.\n");
			}
		}
		/* we can destroy the request at this point, even when this call needs
		 * more than one http request. persistend data (step counter, e.g.) is
		 * stored in req.data */
		if (req.responseData != NULL) {
			free (req.responseData);
		}
		PianoDestroyRequest (&req);
	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);

	return 1;
}
Example #2
0
/*	authenticate user
 */
static bool BarMainLoginUser (BarApp_t *app) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;
	PianoRequestDataLogin_t reqData;
	bool ret;
#if 0
	WaitressHandle_t waithSync;
	char *syncTime;
	unsigned long int syncTimeInt;

	/* skip sync step by fetching time from somewhere else */
	WaitressInit (&waithSync);
	WaitressSetUrl (&waithSync, "http://ridetheclown.com/s2/synctime.php");
	if (app->settings.proxy != NULL && strlen (app->settings.proxy) > 0) {
		WaitressSetProxy (&waithSync, app->settings.proxy);
	}
	wRet = WaitressFetchBuf (&waithSync, &syncTime);
	WaitressFree (&waithSync);
	if (wRet != WAITRESS_RET_OK) {
		BarUiMsg (&app->settings, MSG_ERR, "Unable to sync: %s\n",
				WaitressErrorToStr (wRet));
		return false;
	}

	syncTimeInt = strtoul (syncTime, NULL, 0);
	app->ph.timeOffset = time (NULL) - syncTimeInt;
	free (syncTime);
#endif
	app->ph.timeOffset = -30239998; /* woo! magic number */

	reqData.user = app->settings.username;
	reqData.password = app->settings.password;
	reqData.step = 0;

	BarUiMsg (&app->settings, MSG_INFO, "Login... ");
	ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet);
	BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player,
			NULL, pRet, wRet);
	return ret;
}
Example #3
0
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoStation_t *stations,
                PianoReturn_t pRet, WaitressReturn_t wRet) {
	pid_t chld;
	int pipeFd[2];

	if (settings->eventCmd == NULL) {
		/* nothing to do... */
		return;
	}

	if (pipe (pipeFd) == -1) {
		BarUiMsg (settings, MSG_ERR, "Cannot create eventcmd pipe. (%s)\n", strerror (errno));
		return;
	}

	chld = fork ();
	if (chld == 0) {
		/* child */
		close (pipeFd[1]);
		dup2 (pipeFd[0], fileno (stdin));
		execl (settings->eventCmd, settings->eventCmd, type, (char *) NULL);
		BarUiMsg (settings, MSG_ERR, "Cannot start eventcmd. (%s)\n", strerror (errno));
		close (pipeFd[0]);
		exit (1);
	} else if (chld == -1) {
		BarUiMsg (settings, MSG_ERR, "Cannot fork eventcmd. (%s)\n", strerror (errno));
	} else {
		/* parent */
		int status;
		PianoStation_t *songStation = NULL;
		FILE *pipeWriteFd;

		close (pipeFd[0]);

		pipeWriteFd = fdopen (pipeFd[1], "w");

		if (curSong != NULL && stations != NULL && curStation->isQuickMix) {
			songStation = PianoFindStationById (stations, curSong->stationId);
		}

		fprintf (pipeWriteFd,
				"artist=%s\n"
				"title=%s\n"
				"album=%s\n"
				"coverArt=%s\n"
				"stationName=%s\n"
				"songStationName=%s\n"
				"pRet=%i\n"
				"pRetStr=%s\n"
				"wRet=%i\n"
				"wRetStr=%s\n"
				"songDuration=%lu\n"
				"songPlayed=%lu\n"
				"rating=%i\n"
				"detailUrl=%s\n",
				curSong == NULL ? "" : curSong->artist,
				curSong == NULL ? "" : curSong->title,
				curSong == NULL ? "" : curSong->album,
				curSong == NULL ? "" : curSong->coverArt,
				curStation == NULL ? "" : curStation->name,
				songStation == NULL ? "" : songStation->name,
				pRet,
				PianoErrorToStr (pRet),
				wRet,
				WaitressErrorToStr (wRet),
				player->songDuration,
				player->songPlayed,
				curSong == NULL ? PIANO_RATE_NONE : curSong->rating,
				curSong == NULL ? "" : curSong->detailUrl
				);

		if (stations != NULL) {
			/* send station list */
			PianoStation_t **sortedStations = NULL;
			size_t stationCount;
			sortedStations = BarSortedStations (stations, &stationCount,
					settings->sortOrder);
			assert (sortedStations != NULL);

			fprintf (pipeWriteFd, "stationCount=%zd\n", stationCount);

			for (size_t i = 0; i < stationCount; i++) {
				const PianoStation_t *currStation = sortedStations[i];
				fprintf (pipeWriteFd, "station%zd=%s\n", i,
						currStation->name);
			}
			free (sortedStations);
		} else {
			const char * const msg = "stationCount=0\n";
			fwrite (msg, sizeof (*msg), strlen (msg), pipeWriteFd);
		}
	
		/* closes pipeFd[1] as well */
		fclose (pipeWriteFd);
		/* wait to get rid of the zombie */
		waitpid (chld, &status, 0);
	}
}
Example #4
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano (updates data structures)
 *	@param app handle
 *	@param request type
 *	@param request data
 *	@param stores piano return code
 *	@param stores waitress return code
 *	@return 1 on success, 0 otherwise
 */
int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
		void *data, PianoReturn_t *pRet, WaitressReturn_t *wRet) {
	PianoRequest_t req;

	memset (&req, 0, sizeof (req));

	/* repeat as long as there are http requests to do */
	do {
		req.data = data;

		*pRet = PianoRequest (&app->ph, &req, type);
		if (*pRet != PIANO_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
			PianoDestroyRequest (&req);
			return 0;
		}

		*wRet = BarPianoHttpRequest (&app->waith, &req);
		if (*wRet != WAITRESS_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
			if (req.responseData != NULL) {
				free (req.responseData);
			}
			PianoDestroyRequest (&req);
			return 0;
		}

		*pRet = PianoResponse (&app->ph, &req);
		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
			/* checking for request type avoids infinite loops */
			if (*pRet == PIANO_RET_P_INVALID_AUTH_TOKEN &&
					type != PIANO_REQUEST_LOGIN) {
				/* reauthenticate */
				PianoReturn_t authpRet;
				WaitressReturn_t authwRet;
				PianoRequestDataLogin_t reqData;
				reqData.user = app->settings.username;
				reqData.password = app->settings.password;
				reqData.step = 0;

				BarUiMsg (&app->settings, MSG_NONE, "Reauthentication required... ");
				if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet,
						&authwRet)) {
					*pRet = authpRet;
					*wRet = authwRet;
					if (req.responseData != NULL) {
						free (req.responseData);
					}
					PianoDestroyRequest (&req);
					return 0;
				} else {
					/* try again */
					*pRet = PIANO_RET_CONTINUE_REQUEST;
					BarUiMsg (&app->settings, MSG_INFO, "Trying again... ");
				}
			} else if (*pRet != PIANO_RET_OK) {
				BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
				if (req.responseData != NULL) {
					free (req.responseData);
				}
				PianoDestroyRequest (&req);
				return 0;
			} else {
				BarUiMsg (&app->settings, MSG_NONE, "Ok.\n");
			}
		}
		/* we can destroy the request at this point, even when this call needs
		 * more than one http request. persistent data (step counter, e.g.) is
		 * stored in req.data */
		if (req.responseData != NULL) {
			free (req.responseData);
		}
		PianoDestroyRequest (&req);
	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);

	return 1;
}
Example #5
0
int
MythPianoService::PianoCall(PianoRequestType_t type,
			    void *data,
			    PianoReturn_t *pRet,
			    WaitressReturn_t *wRet) {
  if (!m_Piano)
    return -1;

  PianoRequest_t req;
  memset (&req, 0, sizeof (req));

  /* repeat as long as there are http requests to do */
  do {
    req.data = data;

    *pRet = PianoRequest (m_Piano, &req, type);

    if (*pRet != PIANO_RET_OK) {
      BroadcastMessage("Error: %s\n", PianoErrorToStr (*pRet));
      PianoDestroyRequest (&req);
      return 0;
    }

    *wRet = PianoHttpRequest(&m_Waith, &req);
    if (*wRet != WAITRESS_RET_OK) {
      BroadcastMessage ("Network error: %s\n", WaitressErrorToStr (*wRet));
      if (req.responseData != NULL) {
	free (req.responseData);
      }
      PianoDestroyRequest (&req);
      return 0;
    }

    *pRet = PianoResponse (m_Piano, &req);
    if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
      /* checking for request type avoids infinite loops */
      if (*pRet == PIANO_RET_AUTH_TOKEN_INVALID &&
	  type != PIANO_REQUEST_LOGIN) {
	/* reauthenticate */
        PianoReturn_t authpRet;
        WaitressReturn_t authwRet;
        PianoRequestDataLogin_t reqData;

        QString username = gCoreContext->GetSetting("pandora-username");
        QString password = gCoreContext->GetSetting("pandora-password");

        //wtf really?
        char* usernameBuff = strndup(username.toUtf8().data(), 1024);
        char* passwordBuff = strndup(password.toUtf8().data(), 1024);

        reqData.user = usernameBuff;
        reqData.password = passwordBuff;
        reqData.step = 0;

        BroadcastMessage ("Reauthentication required... ");
        if (!PianoCall(PIANO_REQUEST_LOGIN, &reqData, &authpRet, &authwRet)) {
          *pRet = authpRet;
          *wRet = authwRet;
          if (req.responseData != NULL) {
            free (req.responseData);
          }
          PianoDestroyRequest (&req);
          return 0;
        } else {
          /* try again */
          *pRet = PIANO_RET_CONTINUE_REQUEST;
          BroadcastMessage("Trying again... ");
        }

        // wtf
        free(usernameBuff);
        free(passwordBuff);

      } else if (*pRet != PIANO_RET_OK) {
	BroadcastMessage("Error: %s\n", PianoErrorToStr (*pRet));
	if (req.responseData != NULL) {
	  free (req.responseData);
	}
	PianoDestroyRequest (&req);
	return 0;
      } else {
	BroadcastMessage("Login Ok.\n");
      }
    }
    /* we can destroy the request at this point, even when this call needs
     * more than one http request. persistent data (step counter, e.g.) is
     * stored in req.data */
    if (req.responseData != NULL) {
      free (req.responseData);
    }
    PianoDestroyRequest (&req);
  } while (*pRet == PIANO_RET_CONTINUE_REQUEST);

  return 1;
}
Example #6
0
File: ui.c Project: biorisk/panpigo
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoStation_t *stations,
                PianoReturn_t pRet, WaitressReturn_t wRet) {

	int status;
	PianoStation_t *songStation = NULL;

	if (curSong != NULL && stations != NULL && curStation->isQuickMix) {
		songStation = PianoFindStationById (stations, curSong->stationId);
	}

	printf ("current\tartist=%s\n"
			"current\ttitle=%s\n"
			"current\talbum=%s\n"
			"current\tcoverArt=%s\n"
			"current\tstationName=%s\n"
			"songStationName=%s\n"
			"pRet=%i\n"
			"pRetStr=%s\n"
			"wRet=%i\n"
			"wRetStr=%s\n"
			"songDuration=%lu\n"
			"songPlayed=%lu\n"
			"rating=%i\n"
			"detailUrl=%s\n",
			curSong == NULL ? "" : curSong->artist,
			curSong == NULL ? "" : curSong->title,
			curSong == NULL ? "" : curSong->album,
			curSong == NULL ? "" : curSong->coverArt,
			curStation == NULL ? "" : curStation->name,
			songStation == NULL ? "" : songStation->name,
			pRet,
			PianoErrorToStr (pRet),
			wRet,
			WaitressErrorToStr (wRet),
			player->songDuration,
			player->songPlayed,
			curSong == NULL ? PIANO_RATE_NONE : curSong->rating,
			curSong == NULL ? "" : curSong->detailUrl
			);

	if (stations != NULL) {
		/* send station list */
		PianoStation_t **sortedStations = NULL;
		size_t stationCount;
		sortedStations = BarSortedStations (stations, &stationCount,
				settings->sortOrder);
		assert (sortedStations != NULL);

		printf ("station\tstationCount=%zd\n", stationCount);

		for (size_t i = 0; i < stationCount; i++) {
			const PianoStation_t *currStation = sortedStations[i];
			printf ("station\tstation%zd=%s\n", i,
					currStation->name);
		}

		free (sortedStations);
	}
}
Example #7
0
/*	player thread; for every song a new thread is started
 *	@param audioPlayer structure
 *	@return PLAYER_RET_*
 */
void *BarPlayerThread (void *data) {
	struct audioPlayer *player = data;
	char extraHeaders[32];
	void *ret = PLAYER_RET_OK;
	#ifdef ENABLE_FAAD
	NeAACDecConfigurationPtr conf;
	#endif
	WaitressReturn_t wRet = WAITRESS_RET_ERR;

	/* init handles */
	pthread_mutex_init (&player->pauseMutex, NULL);
	player->waith.data = (void *) player;
	/* extraHeaders will be initialized later */
	player->waith.extraHeaders = extraHeaders;
	player->buffer = malloc (BAR_PLAYER_BUFSIZE);

	switch (player->audioFormat) {
		#ifdef ENABLE_FAAD
		case PIANO_AF_AACPLUS:
			player->aacHandle = NeAACDecOpen();
			/* set aac conf */
			conf = NeAACDecGetCurrentConfiguration(player->aacHandle);
			conf->outputFormat = FAAD_FMT_16BIT;
		    conf->downMatrix = 1;
			NeAACDecSetConfiguration(player->aacHandle, conf);

			player->waith.callback = BarPlayerAACCb;
			break;
		#endif /* ENABLE_FAAD */

		#ifdef ENABLE_MAD
		case PIANO_AF_MP3:
			mad_stream_init (&player->mp3Stream);
			mad_frame_init (&player->mp3Frame);
			mad_synth_init (&player->mp3Synth);

			player->waith.callback = BarPlayerMp3Cb;
			break;
		#endif /* ENABLE_MAD */

		default:
			BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n");
			ret = (void *) PLAYER_RET_HARDFAIL;
			goto cleanup;
			break;
	}
	
	player->mode = PLAYER_INITIALIZED;

	/* This loop should work around song abortions by requesting the
	 * missing part of the song */
	do {
		snprintf (extraHeaders, sizeof (extraHeaders), "Range: bytes=%zu-\r\n",
				player->bytesReceived);
		wRet = WaitressFetchCall (&player->waith);
	} while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT
			|| wRet == WAITRESS_RET_READ_ERR);

	switch (player->audioFormat) {
		#ifdef ENABLE_FAAD
		case PIANO_AF_AACPLUS:
			NeAACDecClose(player->aacHandle);
			free (player->sampleSize);
			break;
		#endif /* ENABLE_FAAD */

		#ifdef ENABLE_MAD
		case PIANO_AF_MP3:
			mad_synth_finish (&player->mp3Synth);
			mad_frame_finish (&player->mp3Frame);
			mad_stream_finish (&player->mp3Stream);
			break;
		#endif /* ENABLE_MAD */

		default:
			/* this should never happen */
			assert (0);
			break;
	}

	if (player->aoError) {
		ret = (void *) PLAYER_RET_HARDFAIL;
	}

	/* Pandora sends broken audio url’s sometimes (“bad request”). ignore them. */
	if (wRet != WAITRESS_RET_OK && wRet != WAITRESS_RET_CB_ABORT) {
		BarUiMsg (player->settings, MSG_ERR, "Cannot access audio file: %s\n",
				WaitressErrorToStr (wRet));
		ret = (void *) PLAYER_RET_SOFTFAIL;
	}

cleanup:
	ao_close (player->audioOutDevice);
	WaitressFree (&player->waith);
	free (player->buffer);

	player->mode = PLAYER_FINISHED_PLAYBACK;

	return ret;
}
Example #8
0
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoReturn_t pRet,
		WaitressReturn_t wRet) {
	pid_t chld;
	char pipeBuf[1024];
	int pipeFd[2];

	if (settings->eventCmd == NULL) {
		/* nothing to do... */
		return;
	}

	/* prepare stdin content */
	memset (pipeBuf, 0, sizeof (pipeBuf));
	snprintf (pipeBuf, sizeof (pipeBuf),
			"artist=%s\n"
			"title=%s\n"
			"album=%s\n"
			"stationName=%s\n"
			"pRet=%i\n"
			"pRetStr=%s\n"
			"wRet=%i\n"
			"wRetStr=%s\n"
			"songDuration=%lu\n"
			"songPlayed=%lu\n"
			"rating=%i\n",
			curSong == NULL ? "" : curSong->artist,
			curSong == NULL ? "" : curSong->title,
			curSong == NULL ? "" : curSong->album,
			curStation == NULL ? "" : curStation->name,
			pRet,
			PianoErrorToStr (pRet),
			wRet,
			WaitressErrorToStr (wRet),
			player->songDuration,
			player->songPlayed,
			curSong == NULL ? PIANO_RATE_NONE : curSong->rating
			);
	
	if (pipe (pipeFd) == -1) {
		BarUiMsg (MSG_ERR, "Cannot create eventcmd pipe. (%s)\n", strerror (errno));
		return;
	}

	chld = fork ();
	if (chld == 0) {
		/* child */
		close (pipeFd[1]);
		dup2 (pipeFd[0], fileno (stdin));
		execl (settings->eventCmd, settings->eventCmd, type, (char *) NULL);
		BarUiMsg (MSG_ERR, "Cannot start eventcmd. (%s)\n", strerror (errno));
		close (pipeFd[0]);
		exit (1);
	} else if (chld == -1) {
		BarUiMsg (MSG_ERR, "Cannot fork eventcmd. (%s)\n", strerror (errno));
	} else {
		/* parent */
		int status;
		close (pipeFd[0]);
		write (pipeFd[1], pipeBuf, strlen (pipeBuf));
		close (pipeFd[1]);
		/* wait to get rid of the zombie */
		waitpid (chld, &status, 0);
	}
}