You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					185 lines
				
				5.3 KiB
			
		
		
			
		
	
	
					185 lines
				
				5.3 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <getopt.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "common/timing.h"
							 | 
						||
| 
								 | 
							
								#include "slplay.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SLEngineItf engineInterface = NULL;
							 | 
						||
| 
								 | 
							
								SLObjectItf outputMix = NULL;
							 | 
						||
| 
								 | 
							
								SLObjectItf engine = NULL;
							 | 
						||
| 
								 | 
							
								uri_player players[32] = {{NULL, NULL, NULL}};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint64_t loop_start = 0;
							 | 
						||
| 
								 | 
							
								uint64_t loop_start_ctx = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uri_player* get_player_by_uri(const char* uri) {
							 | 
						||
| 
								 | 
							
								  for (uri_player *s = players; s->uri != NULL; s++) {
							 | 
						||
| 
								 | 
							
								    if (strcmp(s->uri, uri) == 0) {
							 | 
						||
| 
								 | 
							
								      return s;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uri_player* slplay_create_player_for_uri(const char* uri, char **error) {
							 | 
						||
| 
								 | 
							
								  uri_player player = { uri, NULL, NULL };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SLresult result;
							 | 
						||
| 
								 | 
							
								  SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *) uri};
							 | 
						||
| 
								 | 
							
								  SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
							 | 
						||
| 
								 | 
							
								  SLDataSource audioSrc = {&locUri, &formatMime};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
							 | 
						||
| 
								 | 
							
								  SLDataSink audioSnk = {&outMix, NULL};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*engineInterface)->CreateAudioPlayer(engineInterface, &player.player, &audioSrc, &audioSnk, 0, NULL, NULL);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to create audio player";
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*(player.player))->Realize(player.player, SL_BOOLEAN_FALSE);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to realize audio player";
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*(player.player))->GetInterface(player.player, SL_IID_PLAY, &(player.playInterface));
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to get player interface";
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*(player.playInterface))->SetPlayState(player.playInterface, SL_PLAYSTATE_PAUSED);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to initialize playstate to SL_PLAYSTATE_PAUSED";
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uri_player *p = players;
							 | 
						||
| 
								 | 
							
								  while (p->uri != NULL) {
							 | 
						||
| 
								 | 
							
								    p++;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  *p = player;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return p;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void slplay_setup(char **error) {
							 | 
						||
| 
								 | 
							
								  SLresult result;
							 | 
						||
| 
								 | 
							
								  SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}};
							 | 
						||
| 
								 | 
							
								  result = slCreateEngine(&engine, 1, engineOptions, 0, NULL, NULL);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to create OpenSL engine";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*engine)->Realize(engine, SL_BOOLEAN_FALSE);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to realize OpenSL engine";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*engine)->GetInterface(engine, SL_IID_ENGINE, &engineInterface);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to realize OpenSL engine";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const SLInterfaceID ids[1] = {SL_IID_VOLUME};
							 | 
						||
| 
								 | 
							
								  const SLboolean req[1] = {SL_BOOLEAN_FALSE};
							 | 
						||
| 
								 | 
							
								  result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMix, 1, ids, req);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to create output mix";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to realize output mix";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void slplay_destroy() {
							 | 
						||
| 
								 | 
							
								  for (uri_player *player = players; player->uri != NULL; player++) {
							 | 
						||
| 
								 | 
							
								    if (player->player) {
							 | 
						||
| 
								 | 
							
								      (*(player->player))->Destroy(player->player);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  (*outputMix)->Destroy(outputMix);
							 | 
						||
| 
								 | 
							
								  (*engine)->Destroy(engine);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void slplay_stop(uri_player* player, char **error) {
							 | 
						||
| 
								 | 
							
								  SLPlayItf playInterface = player->playInterface;
							 | 
						||
| 
								 | 
							
								  SLresult result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // stop a loop
							 | 
						||
| 
								 | 
							
								  loop_start = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to set SL_PLAYSTATE_STOPPED";
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void slplay_stop_uri(const char* uri, char **error) {
							 | 
						||
| 
								 | 
							
								  uri_player* player = get_player_by_uri(uri);
							 | 
						||
| 
								 | 
							
								  slplay_stop(player, error);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) {
							 | 
						||
| 
								 | 
							
								  uint64_t cb_loop_start = *((uint64_t*)context);
							 | 
						||
| 
								 | 
							
								  if (event == SL_PLAYEVENT_HEADATEND && cb_loop_start == loop_start) {
							 | 
						||
| 
								 | 
							
								    (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
							 | 
						||
| 
								 | 
							
								    (*playItf)->SetMarkerPosition(playItf, 0);
							 | 
						||
| 
								 | 
							
								    (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void slplay_play (const char *uri, bool loop, char **error) {
							 | 
						||
| 
								 | 
							
								  SLresult result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uri_player* player = get_player_by_uri(uri);
							 | 
						||
| 
								 | 
							
								  if (player == NULL) {
							 | 
						||
| 
								 | 
							
								    player = slplay_create_player_for_uri(uri, error);
							 | 
						||
| 
								 | 
							
								    if (*error) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SLPlayItf playInterface = player->playInterface;
							 | 
						||
| 
								 | 
							
								  if (loop) {
							 | 
						||
| 
								 | 
							
								    loop_start = nanos_since_boot();
							 | 
						||
| 
								 | 
							
								    loop_start_ctx = loop_start;
							 | 
						||
| 
								 | 
							
								    result = (*playInterface)->RegisterCallback(playInterface, slplay_callback, &loop_start_ctx);
							 | 
						||
| 
								 | 
							
								    if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								      char error[64];
							 | 
						||
| 
								 | 
							
								      snprintf(error, sizeof(error), "Failed to register callback. %d", result);
							 | 
						||
| 
								 | 
							
								      *error = error[0];
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    result = (*playInterface)->SetCallbackEventsMask(playInterface, SL_PLAYEVENT_HEADATEND);
							 | 
						||
| 
								 | 
							
								    if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								      *error = "Failed to set callback event mask";
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Reset the audio player
							 | 
						||
| 
								 | 
							
								  result = (*playInterface)->ClearMarkerPosition(playInterface);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to clear marker position";
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED);
							 | 
						||
| 
								 | 
							
								  result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_STOPPED);
							 | 
						||
| 
								 | 
							
								  result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PLAYING);
							 | 
						||
| 
								 | 
							
								  if (result != SL_RESULT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								    *error = "Failed to set SL_PLAYSTATE_PLAYING";
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |