How to record audio with Smart Eye Glass? - android

I am developing an audio recorder with Sony Smart Eyeglass, but it does not work well.
My application records just a voice from phone microphone, not from Smart Eyeglass microphone.
I'd like to record a voice just only from Smart Eyeglass microphone.
Any ideas?
Here is my code.
public class AudioRecordControl extends ControlExtension {
private final AudioManager _audioManager;
private final File _file;
private SmartEyeglassControlUtils _util;
private static final int SMARTEYEGLASS_API_VERSION = 1;
private MediaRecorder _recorder;
private MediaPlayer _player;
enum State {
STOP,
RECORDING,
PLAYING,
}
private State _state;
public AudioRecordControl(Context context, String hostAppPackageName) {
super(context, hostAppPackageName);
_util = new SmartEyeglassControlUtils(hostAppPackageName, new SmartEyeglassEventListener() {
#Override
public void onDialogClosed(int code) {
super.onDialogClosed(code);
doNextAction(code);
showCurrentLayout();
}
});
_util.setRequiredApiVersion(SMARTEYEGLASS_API_VERSION);
_util.activate(context);
_audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
_audioManager.setMode(AudioManager.MODE_IN_CALL);
_audioManager.startBluetoothSco();
_state = State.STOP;
File directoryPath = Environment.getExternalStoragePublicDirectory("AudioRecord");
if (!directoryPath.exists()) {
if (!directoryPath.mkdirs()) {
Log.e(Constants.LOG_TAG, "failed to create directory '" + directoryPath.toString() + "'");
}
}
_file = new File(directoryPath, "record.3gp");
showCurrentLayout();
}
private void showCurrentLayout() {
showLayout(R.layout.layout, null);
switch (_state) {
case STOP:
String[] buttons;
if (_file.exists()) {
buttons = new String[]{
mContext.getString(R.string.record),
mContext.getString(R.string.play)};
} else {
buttons = new String[]{mContext.getString(R.string.record)};
}
_util.showDialogMessage(
mContext.getString(R.string.title),
mContext.getString(R.string.choose_one), buttons);
break;
case RECORDING:
_util.showDialogMessage(
mContext.getString(R.string.stop_recording),
com.sony.smarteyeglass.SmartEyeglassControl.Intents.DIALOG_MODE_OK);
break;
case PLAYING:
_util.showDialogMessage(
mContext.getString(R.string.stop_playing),
com.sony.smarteyeglass.SmartEyeglassControl.Intents.DIALOG_MODE_OK);
break;
default:
break;
}
}
private void doNextAction(int code) {
if (code == -1) {
stopRequest();
}
showLayout(R.layout.layout, null);
switch (_state) {
case STOP:
if (code == 0) {
Log.d(Constants.LOG_TAG, "start recording");
try {
_startRecording();
} catch (IOException e) {
Log.e(Constants.LOG_TAG, "failed to record", e);
_util.showDialogMessage(
mContext.getString(R.string.failed_to_record),
SmartEyeglassControl.Intents.DIALOG_MODE_TIMEOUT);
_recorder = null;
return;
}
_state = State.RECORDING;
} else if (code == 1) {
Log.d(Constants.LOG_TAG, "start playing");
try {
_play();
} catch (IOException e) {
Log.e(Constants.LOG_TAG, "failed to play", e);
_util.showDialogMessage(
mContext.getString(R.string.failed_to_pla),
SmartEyeglassControl.Intents.DIALOG_MODE_TIMEOUT);
_player = null;
return;
}
_state = State.PLAYING;
} else {
stopRequest();
}
break;
case RECORDING:
Log.d(Constants.LOG_TAG, "stop recording");
_stopRecord();
_state = State.STOP;
break;
case PLAYING:
Log.d(Constants.LOG_TAG, "stop playing");
_stopPlay();
_state = State.STOP;
break;
default:
_state = State.STOP;
break;
}
}
private void _startRecording() throws IOException {
if (_recorder == null) {
_recorder = new MediaRecorder();
_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
_recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
_recorder.setOutputFile(String.valueOf(_file));
_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
_recorder.prepare();
_recorder.start();
}
}
private void _stopRecord() {
if (_recorder != null) {
_recorder.stop();
_recorder.reset();
_recorder.release();
_recorder = null;
}
}
private void _play() throws IOException {
if (_player == null) {
_player = new MediaPlayer();
_player.setDataSource(String.valueOf(_file));
_player.prepare();
_player.start();
}
}
private void _stopPlay() {
if (_player != null) {
_player.stop();
_player.reset();
_player.release();
_player= null;
}
}
#Override
public void onResume() {
showCurrentLayout();
}
#Override
public void onTap(int action, long timeStamp) {
super.onTap(action, timeStamp);
showCurrentLayout();
}
#Override
public void onDestroy() {
Log.d(Constants.LOG_TAG, "Control On Desuptroy");
_util.deactivate();
_audioManager.setMode(AudioManager.MODE_NORMAL);
_audioManager.stopBluetoothSco();
}
}

Some phones require an extra method call after setMode:
private AudioManager m_amAudioManager;
m_amAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
m_amAudioManager.setMode(AudioManager.MODE_IN_CALL);
m_amAudioManager.setSpeakerphoneOn(false);
To learn more about rest of the operation, there is a guide on Audio I/O with SmartEyeglass:
https://developer.sony.com/develop/wearables/smarteyeglass-sdk/guides/use-bluetooth-for-audio-io/

Would you put your recording code in the Activity and test without using the eyeglass first?
As you are using the phone's capability only, it should work if you can record from microphone in Activity alone. Please ensure you have added uses-permission tag in AndroidManifest.xml

Related

Android: MediaPlayer onPrepared Not Working

So I'm attempting to have an audio stream play via the MediaPlayer Class. I was able to play the stream when only it in a Activity. Now I'm trying to have it work via a Service. I added comments to each functions so that I can track what its doing, everything seems to work fine, services get binded and all but now the onPrepared doesn't seems to initiate. I get no error until I try to stop the stream and says was stopped in State 4. I've tried reaching all possible cause and can't seem to find problem. I even build the unprepared within a new MediaPlayer class and still onPrepared doesn't get called. I've only put the service code below since all the other components work.
Any help would be great, Thank you.
Service:
public class StreamService extends Service
implements MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener,
AudioManager.OnAudioFocusChangeListener {
private static final String TAG = "TESTING";
private static final String TAGPlus = "Stream Service - ";
private static final String ACTION_PLAY = "PLAY";
private static final String ACTION_PREV = "PREV";
private static final String ACTION_NEXT = "NEXT";
public static MediaPlayer streamPlayer;
ActionPlaying actionPlaying;
AudioManager audioManager;
static ServiceState serviceState = StreamService.ServiceState.BLANK;
private boolean pausedTemporarilyDueToAudioFocus = false;
private boolean loweredVolumeDueToAudioFocus = false;
private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private BecomingNoisyReceiver myNoisyAudioStreamReceiver = new BecomingNoisyReceiver();
IBinder mBinder = new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG,TAGPlus+"onBind - "+intent);
return mBinder;
}
public class MyBinder extends Binder{
public StreamService getService(){
return StreamService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG,TAGPlus+"onCreate..."+serviceState);
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
initNoisyReceiver();
initMusicPlayer();
}
private void initNoisyReceiver() {
Log.d(TAG,TAGPlus+"initNoisyReceiver..."+serviceState);
//Handles headphones coming unplugged. cannot be done through a manifest receiver
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
filter.addAction(Intent.ACTION_HEADSET_PLUG);
registerReceiver(myNoisyAudioStreamReceiver, filter);
}
public void initMusicPlayer() {
Log.d(TAG,TAGPlus+"initMusicPlayer - "+serviceState+" - "+streamPlayer);
if (streamPlayer == null) {
serviceState = ServiceState.PREPARING;
streamPlayer = new MediaPlayer();
}
Log.d(TAG,TAGPlus+"initMusicPlayer - "+serviceState+" - "+streamPlayer);
streamPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
streamPlayer.setAudioAttributes(
new AudioAttributes
.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
// These are the events that will "wake us up"
//streamPlayer.setOnPreparedListener(this); // player initialized
streamPlayer.setOnCompletionListener(this); // song completed
streamPlayer.setOnErrorListener(this);
streamPlayer.setOnPreparedListener(this);
//setStreamDataSource();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getStringExtra("myActionName");
Log.d(TAG,TAGPlus+"onStartCommand... - "+action+ "");
if (action != null) {
switch (action) {
case ACTION_PLAY:
if(actionPlaying != null)
{
actionPlaying.playClicked();
}
break;
case ACTION_PREV:
if(actionPlaying != null)
{
actionPlaying.prevClicked();
}
break;
case ACTION_NEXT:
if(actionPlaying != null)
{
actionPlaying.nextClicked();
}
break;
default:
}
}
return START_STICKY;
}
public void setStreamDataSource() {
Log.d(TAG,TAGPlus+"Setting DataSource... - "+streamPlayer+"");
if (streamPlayer == null) {
Log.d(TAG,TAGPlus+"MediaPlayer null. Call initMusicPlayer");
initMusicPlayer();
}
//streamPlayer.stop();
streamPlayer.reset();
//String url = "http://nap.casthost.net:8800/stream";
try {
streamPlayer.setDataSource("http://nap.casthost.net:8800/stream.mp3");
Log.d(TAG,TAGPlus+"Setting DataSource - Source Assigned...");
} catch (IOException e) {
Log.e(TAG, "IOException: couldn't start stream");
e.printStackTrace();
}
streamPlayer.prepareAsync();
}
public void playStream() {
Log.d(TAG,TAGPlus+"playStream... ");
String url = "http://nap.casthost.net:8800/stream.mp3";
streamPlayer.reset();
try {
streamPlayer.setDataSource(url);
} catch (IOException e) {e.printStackTrace();}
streamPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.d(TAG,TAGPlus+"onPrepared..."+mediaPlayer);
serviceState = ServiceState.PREPARED;
streamPlayer.start();
serviceState = ServiceState.PLAYING;
}
});
streamPlayer.prepareAsync();
}
public void startStream() {
Log.d(TAG,TAGPlus+"startStream... "+serviceState+" - "+streamPlayer);
if (serviceState != ServiceState.PREPARED)
setStreamDataSource();
//startMusicPlayer();
playStream();
}
public void stopStream() {
Log.d(TAG,TAGPlus+"stopStream... "+serviceState+"");
serviceState = ServiceState.STOPPED;
stopMusicPlayer();
}
public void startMusicPlayer() {
Log.d(TAG,TAGPlus+"startMusicPlayer... "+serviceState+"");
if (serviceState == ServiceState.PLAYING)
return;
streamPlayer.start();
}
public void stopMusicPlayer() {
Log.d(TAG,TAGPlus+"stopMusicPlayer..."+streamPlayer);
if (streamPlayer == null)
return;
streamPlayer.stop();
serviceState = ServiceState.STOPPED;
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.d(TAG,TAGPlus+"onPrepared..."+serviceState+" - "+mediaPlayer);
serviceState = ServiceState.PREPARED;
streamPlayer.start();
}
#Override
public void onDestroy() {
super.onDestroy();
streamPlayer.release();
streamPlayer = null;
//cancelNotification();
if (audioManager != null)
audioManager.abandonAudioFocus(this);
stopMusicPlayer();
unregisterReceiver(myNoisyAudioStreamReceiver);
}
public void setCallback(ActionPlaying actionPlaying) {
Log.d(TAG,TAGPlus+"setCallback...");
this.actionPlaying = actionPlaying;
}
private boolean requestAudioFocus() {
Log.d(TAG,TAGPlus+"requestAudioFocus... ");
//Request audio focus for playback
int result = audioManager.requestAudioFocus(
this,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
//Check if audio focus was granted. If not, stop the service.
return (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
}
#Override
public void onAudioFocusChange(int i) {
Log.d(TAG,TAGPlus+"onAudioFocusChange..."+i);
switch (i) {
// Yay, gained audio focus! Either from losing it for
// a long or short periods of time.
case AudioManager.AUDIOFOCUS_GAIN:
if (streamPlayer == null)
initMusicPlayer();
if (pausedTemporarilyDueToAudioFocus) {
pausedTemporarilyDueToAudioFocus = false;
//unpausePlayer();
}
if (loweredVolumeDueToAudioFocus) {
loweredVolumeDueToAudioFocus = false;
streamPlayer.setVolume(1.0f, 1.0f);
}
break;
// Damn, lost the audio focus for a (presumable) long time
case AudioManager.AUDIOFOCUS_LOSS:
//stopMusicPlayer();
break;
// Just lost audio focus but will get it back shortly
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (!isPaused()) {
//pausePlayer();
pausedTemporarilyDueToAudioFocus = true;
}
break;
// Temporarily lost audio focus but I can keep it playing
// at a low volume instead of stopping completely
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Log.w(TAG, "audiofocus loss transient can duck");
streamPlayer.setVolume(0.1f, 0.1f);
loweredVolumeDueToAudioFocus = true;
break;
default:
throw new IllegalStateException("Unexpected value: " + i);
}
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
Log.d(TAG,TAGPlus+"onCompletion..."+mediaPlayer);
serviceState = ServiceState.PLAYING;
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
Log.d(TAG,TAGPlus+"onError...");
mediaPlayer.reset();
streamPlayer.reset();
return false;
}
public boolean isPaused() {
Log.d(TAG,TAGPlus+"isPaused...");
return serviceState == ServiceState.STOPPED;
}
enum ServiceState {
BLANK,
PREPARING,
PREPARED,
PLAYING,
STOPPED
}
}

NullPointerException in `BluetoothAdapter` when startService() is invoked [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
Error I'm getting null point exception in Bluetooth when I'm starting a service.
LiveFragment.class
public class LiveFragment extends Fragment {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
private BluetoothAdapter mBluetoothAdapter =null;
public BluetoothChatService mChatService = null;
private PowerManager.WakeLock wakeLock = null;
private PowerManager powerManager = null;
private String mConnectedDeviceName = null;
private boolean isServiceBound;
private boolean preRequisites = true;
private SharedPreferences prefs;
private BroadcastReceiver broadcastReceiver;
private Context c;
private AbstractGatewayService ab;
protected ImageView blue_onoffBut, gps_Button, obd_inidca, ss_button, bluetooth_indicator, gps_indicator,obd_connectButt;
protected TextView ss_Status,btStatusTextView,obdStatusTextView,gpsStatusTextView;
private LinearLayout vv;
protected BluetoothSocket sock = null;
public LiveFragment() {
// Required empty public constructor
}
private final Runnable mQueueCommands = new Runnable() {
public void run() {
Log.d(TAG, "Runnable mQueueCommands ()");
if (ab != null && ab.isRunning() && ab.queueEmpty()) {
queueCommands();
}
// run again in period defined in preferences
new Handler().postDelayed(mQueueCommands, 4000);
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_live, container, false);
blue_onoffBut = (ImageView) view.findViewById(R.id.blutooth_butoon);
gps_Button = (ImageView) view.findViewById(R.id.gps_button);
obd_inidca = (ImageView) view.findViewById(R.id.obd_Indicator);
ss_button = (ImageView) view.findViewById(ssButton);
gps_indicator = (ImageView) view.findViewById(R.id.gps_indicator);
bluetooth_indicator = (ImageView) view.findViewById(R.id.bluetooth_indicator);
obd_connectButt = (ImageView) view.findViewById(R.id.Obd_Connect_Button);
ss_Status = (TextView) view.findViewById(R.id.statusTx);
btStatusTextView = (TextView) view.findViewById(R.id.blue);
obdStatusTextView = (TextView) view.findViewById(R.id.obd);
gpsStatusTextView = (TextView) view.findViewById(R.id.gps);
vv = (LinearLayout) view.findViewById(R.id.fragment_live_layout);
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
if (mBluetoothAdapter.isEnabled()) {
bluetooth_indicator.setImageResource(R.drawable.green_circle);
} else {
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
gps_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
buildAlertMessageNoGps();
}
else {
showToast("Already GPS is ON");
}
}
});
blue_onoffBut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
showToast("Bluetooth Turned ON"+"\n"+"Connect Your OBD now");
bluetooth_indicator.setImageResource(R.drawable.green_circle);
mChatService = new BluetoothChatService(getActivity(), mHandler);
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
} else if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
mBluetoothAdapter.cancelDiscovery();
obd_inidca.setImageResource(R.drawable.red_circle);
showToast("Bluetooth Turned OFF");
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
});
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mBluetoothAdapter.isEnabled() && mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
startLiveData();
} else if (!mBluetoothAdapter.isEnabled()) {
showToast("Turn ON Bluetooth to Continue");
}
else if (!(mChatService.getState() == BluetoothChatService.STATE_CONNECTED)){
showToast("Select your OBD to Start ");
}
}
});
obd_connectButt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mBluetoothAdapter.isEnabled()) {
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
}
else if (!mBluetoothAdapter.isEnabled()){
showToast("Turn ON Bluetooth to Connect OBD");
}
}
});
return view;
}
private ServiceConnection serviceConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.d(TAG, className.toString() + " service is bound");
isServiceBound = true;
ab = ((AbstractGatewayService.AbstractGatewayServiceBinder) binder).getService();
ab.setContext(getActivity());
Log.d(TAG, "Starting live data");
try {
ab.startService();
if (preRequisites)
btStatusTextView.setText("Connected");
} catch (IOException ioe) {
Log.e(TAG, "Failure Starting live data");
btStatusTextView.setText("Connection failed");
doUnbindService();
}
}
#Override
protected Object clone() throws CloneNotSupportedException {
Log.d(TAG, "CloneNotSupportedException ");
return super.clone();
}
#Override
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, className.toString() + " service is unbound");
isServiceBound = false;
}
};
public static String LookUpCommand(String txt) {
Log.d(TAG, "LookUpCommand() ");
for (AvailableCommandNames item : AvailableCommandNames.values()) {
if (item.getValue().equals(txt)) return item.name();
}
return txt;
}
public void updateTextView(final TextView view, final String txt) {
Log.d(TAG, "updateTextView() ");
new Handler().post(new Runnable() {
public void run() {
view.setText(txt);
}
});
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void stateUpdate(ObdCommandJob job) {
final String cmdName = job.getCommand().getName();
String cmdResult = "";
final String cmdID = LookUpCommand(cmdName);
Log.d(TAG, "stateUpdate() ");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR)) {
cmdResult = job.getCommand().getResult();
if (cmdResult != null && isServiceBound) {
obdStatusTextView.setText(cmdResult.toLowerCase());
}
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE)) {
if (isServiceBound)
stopLiveData();
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED)) {
cmdResult = "NA";
} else {
cmdResult = job.getCommand().getFormattedResult();
if (isServiceBound)
obdStatusTextView.setText("Receiving data...");
}
cmdResult.replace("NODATA", "0");
if (vv.findViewWithTag(cmdID) != null) {
TextView existingTV = (TextView) vv.findViewWithTag(cmdID);
existingTV.setText(cmdResult);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
FragmentActivity activity = getActivity();
Toast.makeText(activity, "No Bluetooth Feature in Device", Toast.LENGTH_LONG).show();
activity.finish();
}
}
#Override
public void onStart() {
super.onStart();
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.red_circle);
}
if(mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.disable();
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
#Override
public void onResume() {
super.onResume();
powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ObdReader");
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.green_circle);
} else {
gps_indicator.setImageResource(R.drawable.red_circle);
}
EventBus.getDefault().register(this);
if(mBluetoothAdapter.isEnabled()) {
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "Pausing..");
releaseWakeLockIfHeld();
EventBus.getDefault().unregister(this);
}
private void showToast(String message) {
final Toast toast = Toast.makeText(getContext(), message, Toast.LENGTH_SHORT);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
}
}, 500);
}
#Override
public void onDestroy() {
/* unregisterReceiver(mReceiver);*/
super.onDestroy();
releaseWakeLockIfHeld();
if (mChatService != null) {
mChatService.stop();
}
if (isServiceBound) {
doUnbindService();
}
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
showToast("Take Care!");
}
private void startLiveData() {
if (mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
Log.d(TAG, "Starting live data..");
ss_Status.setText("Stop");
ss_Status.setTextColor(getResources().getColor(R.color.colorRed));
wakeLock.acquire();
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
stopLiveData();
}
});
doBindService();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver), new IntentFilter(OBD_GATEWAY_SERVICE));
new Handler().post(mQueueCommands);
}
}
private void stopLiveData() {
Log.d(TAG, "Stopping live data..");
releaseWakeLockIfHeld();
new Handler().removeCallbacks(mQueueCommands);
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
startLiveData();
}
});
doUnbindService();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
private void queueCommands() {
Log.d(TAG, "LiveFragment queueCommands() ");
if (isServiceBound) {
for (ObdCommand Command : ObdConfig.getCommands()) {
if (prefs.getBoolean(Command.getName(), true))
ab.queueJob(new ObdCommandJob(Command));
}
}
}
private void doBindService() {
if (!isServiceBound) {
Log.d(TAG, "Binding OBD service..");
if (preRequisites) {
btStatusTextView.setText("Connecting.....");
Intent serviceIntent = new Intent(getActivity(),ObdGatewayService.class);
getActivity().bindService(serviceIntent, serviceConn, Context.BIND_AUTO_CREATE);
}
}
}
private void doUnbindService() {
if (isServiceBound) {
if (ab.isRunning()) {
ab.stopService();
if (preRequisites)
btStatusTextView.setText("Ready...");
}
Log.d(TAG, "Unbinding OBD service..");
getActivity().unbindService(serviceConn);
isServiceBound = false;
obdStatusTextView.setText("Disconnected");
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
FragmentActivity activity = getActivity();
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
obd_inidca.setImageResource(R.drawable.green_circle);
break;
case BluetoothChatService.STATE_CONNECTING:
obd_inidca.setImageResource(R.drawable.orange_circle);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
obd_inidca.setImageResource(R.drawable.red_circle);
break;
}
break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
if (null != activity) {
Toast.makeText(activity, "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
obd_inidca.setImageResource(R.drawable.green_circle);
}
break;
case Constants.MESSAGE_TOAST:
if (null != activity) {
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
try {
connectDevice(data, true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void connectDevice(Intent data, boolean secure) throws IOException {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice dev = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(dev, secure);
}.
This is ObdGateway service class:
public class ObdGatewayService extends AbstractGatewayService {
private static final String TAG = ObdGatewayService.class.getName();
#Inject
SharedPreferences prefs;
private BluetoothDevice dev = null;
private BluetoothSocket sock = null;
private BluetoothChatService mChatservice = null;
private BluetoothAdapter bluetoothAdapter =null;
public final static String JOB_NAME_STAMP = "Name";
public final static String JOB_STATE_STAMP = "State";
public final static String JOB_RESULT_STAMP = "Result";
public final static String JOB_FORMATED_RESULT_STAMP = "Formated REsult";
public final static String OBD_GATEWAY_SERVICE = "com.samplersoft.saz.Obd.ObdGatewayService";
public void startService() throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// get the remote Bluetooth device
if(mChatservice.getState() != BluetoothChatService.STATE_CONNECTED){
Toast.makeText(ctx, "No Bluetooth device selected", Toast.LENGTH_LONG).show();
// log error
Log.e(TAG, "No Bluetooth device has been selected.");
stopService();
throw new IOException();
}
else
{
Log.d(TAG, "Stopping Bluetooth discovery.");
bluetoothAdapter.cancelDiscovery();
try {
startObdConnection();
} catch (Exception e) {
Log.e(
TAG,
"There was an error while establishing connection. -> "
+ e.getMessage()
);
// in case of failure, stop this service.
stopService();
throw new IOException();
}
}
}
private void startObdConnection() throws IOException {
Log.d(TAG, "Starting OBD connection..");
isRunning = true;
if(mChatservice.getState() == BluetoothChatService.STATE_CONNECTED){
// Let's configure the connection.
Log.d(TAG, "Queueing jobs for connection configuration..");
queueJob(new ObdCommandJob(new ObdResetCommand()));
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new LineFeedOffCommand()));
queueJob(new ObdCommandJob(new TimeoutCommand(62)));
// Get protocol from preferences
queueJob(new ObdCommandJob(new SelectProtocolCommand(ObdProtocols.valueOf("AUTO"))));
// Job for returning dummy data
queueJob(new ObdCommandJob(new AmbientAirTemperatureCommand()));
queueCounter = 0L;
Log.d(TAG, "Initialization jobs queued.");
}
else {
stopService();
throw new IOException();
}
}
#Override
public void queueJob(ObdCommandJob job) {
// This is a good place to enforce the imperial units option
//job.getCommand().useImperialUnits(prefs.getBoolean(ConfigActivity.IMPERIAL_UNITS_KEY, false));
// Now we can pass it along
super.queueJob(job);
}
protected void executeQueue() throws InterruptedException {
Log.d(TAG, "Executing queue..");
while (!Thread.currentThread().isInterrupted()) {
ObdCommandJob job = null;
try {
job = jobsQueue.take();
// log job
Log.d(TAG, "Taking job[" + job.getId() + "] from queue..");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NEW)) {
Log.d(TAG, "Job state is NEW. Run it..");
job.setState(ObdCommandJob.ObdCommandJobState.RUNNING);
if (sock.isConnected()) {
job.getCommand().run(sock.getInputStream(), sock.getOutputStream());
} else {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
Log.e(TAG, "Can't run command on a closed socket.");
}
} else
// log not new job
Log.e(TAG,
"Job state was not new, so it shouldn't be in queue. BUG ALERT!");
} catch (InterruptedException i) {
Thread.currentThread().interrupt();
} catch (UnsupportedCommandException u) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED);
}
Log.d(TAG, "Command not supported. -> " + u.getMessage());
} catch (IOException io) {
if (job != null) {
if(io.getMessage().contains("Broken pipe"))
job.setState(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE);
else
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "IO error. -> " + io.getMessage());
} catch (Exception e) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "Failed to run command. -> " + e.getMessage());
}
ObdCommandJob job2 = job;
if(job2 !=null)
EventBus.getDefault().post(job2);
}
}
public void stopService() {
Log.d(TAG, "Stopping service..");
jobsQueue.clear();
isRunning = false;
if (sock != null)
// close socket
try {
sock.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
// kill service
stopSelf();
}
public boolean isRunning() {
return isRunning;
}
}.
This is Abstract Class where service method gets called from from Livefragment Class from serivceConnection().
public abstract class AbstractGatewayService extends RoboService {
private static final String TAG = AbstractGatewayService.class.getName();
private final IBinder binder = new AbstractGatewayServiceBinder();
protected Context ctx;
protected boolean isRunning = false;
protected Long queueCounter = 0L;
protected BlockingQueue<ObdCommandJob> jobsQueue = new LinkedBlockingQueue<>();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
executeQueue();
} catch (InterruptedException e) {
t.interrupt();
}
}
});
protected LocalBroadcastManager broadcastManager;
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Creating service..");
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
t.start();
Log.d(TAG, "Service created.");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroying service...");
t.interrupt();
broadcastManager = LocalBroadcastManager.getInstance(this);
Log.d(TAG, "Service destroyed.");
}
public boolean isRunning() {
return isRunning;
}
public boolean queueEmpty() {
return jobsQueue.isEmpty();
}
public void queueJob(ObdCommandJob job) {
queueCounter++;
Log.d(TAG, "Adding job[" + queueCounter + "] to queue..");
job.setId(queueCounter);
try {
jobsQueue.put(job);
Log.d(TAG, "Job queued successfully.");
} catch (InterruptedException e) {
job.setState(ObdCommandJob.ObdCommandJobState.QUEUE_ERROR);
Log.e(TAG, "Failed to queue job.");
}
}
public void setContext(Context c) {
ctx = c;
}
abstract protected void executeQueue() throws InterruptedException;
abstract public void startService() throws IOException;
abstract public void stopService();
public class AbstractGatewayServiceBinder extends Binder {
public AbstractGatewayService getService() {
return AbstractGatewayService.this;
}
}
}.
You are getting the exception because in class ObdGatewayService your class member mChatservice is not the same as mChatservice in class LiveFragment
They are just different member variables
mChatservice gets assigned like this in your Fragment
mChatService = new BluetoothChatService(getActivity(), mHandler);
You need to pass this reference to ObdGatewayService 's startService() like this where ever you are instantiating/invoking it:-
ObdGatewayService ogs;
....
ogs.startservice(mChatservice); // This is fragment's member reference
And in ObdGatewayService you have to assign it accordingly:-
public void startService(BluetoothChatService _mChatservice) throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mChatservice = _mChatservice //Assignment YOU ARE MISSING THIS
.......
.......
}

How can i bind my media player activity with existing media player service?

I know similar kind of question has been asked before, but none of them are helping me. I am building a music player in which I want to connect my Music through my music player like play, pause etc. Currently, media player service is connected with playlist activity but I have custom designed my media player and I am not able to connect it to the service class.
my MusicPlayer Activity is like this:
public class MusicPlayer extends AppCompatActivity implements PlaylistFragment.OnFragmentInteractionListener{
public static final String Broadcast_PLAY_NEW_AUDIO = "com.example.anuj.musicmetest.PlayNewAudio";
ImageView buttonPlayToggle;
MediaPlayer mediaPlayer;
MediaPlayerService player;
boolean serviceBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
player = binder.getService();
serviceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
serviceBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Music Player");
buttonPlayToggle = (ImageView) findViewById(R.id.button_play_toggle);
buttonPlayToggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mediaPlayer == null) return;
if (mediaPlayer.isPlaying()) {
updatePlayToggle(true);
mediaPlayer.pause();
} else {
updatePlayToggle(false);
mediaPlayer.start();
}
}
});
if (!serviceBound) {
Intent playerIntent = new Intent(this, MediaPlayerService.class);
startService(playerIntent);
bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} else {
Intent broadcastIntent = new Intent(Broadcast_PLAY_NEW_AUDIO);
sendBroadcast(broadcastIntent);
}
}
public void updatePlayToggle(boolean play) {
buttonPlayToggle.setImageResource(play ? R.drawable.ic_pause : R.drawable.ic_play);
}
My ServicecClass is like this:
public class MediaPlayerService extends Service implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnInfoListener, MediaPlayer.OnBufferingUpdateListener,
AudioManager.OnAudioFocusChangeListener {
public static final String ACTION_PLAY = "com.example.anuj.musicmetest.ACTION_PLAY";
public static final String ACTION_PAUSE = "com.example.anuj.musicmetest.ACTION_PAUSE";
public static final String ACTION_PREVIOUS = "com.example.anuj.musicmetest.ACTION_PREVIOUS";
public static final String ACTION_NEXT = "com.example.anuj.musicmetest.ACTION_NEXT";
public static final String ACTION_STOP = "com.example.anuj.musicmetest.ACTION_STOP";
private MediaPlayer mediaPlayer;
private MediaSessionManager mediaSessionManager;
private MediaSessionCompat mediaSession;
private MediaControllerCompat.TransportControls transportControls;
private static final int NOTIFICATION_ID = 101;
//Used to pause/resume MediaPlayer
private int resumePosition;
//AudioFocus
private AudioManager audioManager;
// Binder given to clients
private final IBinder iBinder = new LocalBinder();
private ArrayList<Audio> audioList;
private int audioIndex = -1;
private Audio activeAudio; //an object on the currently playing audio
//Handle incoming phone calls
private boolean ongoingCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
/**
* Service lifecycle methods
*/
#Override
public IBinder onBind(Intent intent) {
return iBinder;
}
#Override
public void onCreate() {
super.onCreate();
callStateListener();
//ACTION_AUDIO_BECOMING_NOISY -- change in audio outputs -- BroadcastReceiver
registerBecomingNoisyReceiver();
//Listen for new Audio to play -- BroadcastReceiver
register_playNewAudio();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
//Load data from SharedPreferences
StorageUtil storage = new StorageUtil(getApplicationContext());
audioList = storage.loadAudio();
audioIndex = storage.loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size()) {
//index is in a valid range
activeAudio = audioList.get(audioIndex);
} else {
stopSelf();
}
} catch (NullPointerException e) {
stopSelf();
}
//Request audio focus
if (!requestAudioFocus()) {
//Could not gain focus
stopSelf();
}
if (mediaSessionManager == null) {
try {
initMediaSession();
initMediaPlayer();
} catch (RemoteException e) {
e.printStackTrace();
stopSelf();
}
buildNotification(PlaybackStatus.PLAYING);
}
//Handle Intent action from MediaSession.TransportControls
handleIncomingActions(intent);
return super.onStartCommand(intent, flags, startId);
}
#Override
public boolean onUnbind(Intent intent) {
mediaSession.release();
removeNotification();
return super.onUnbind(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
stopMedia();
mediaPlayer.release();
}
removeAudioFocus();
//Disable the PhoneStateListener
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
removeNotification();
//unregister BroadcastReceivers
unregisterReceiver(becomingNoisyReceiver);
unregisterReceiver(playNewAudio);
//clear cached playlist
new StorageUtil(getApplicationContext()).clearCachedAudioPlaylist();
}
/**
* Service Binder
*/
public class LocalBinder extends Binder {
public MediaPlayerService getService() {
// Return this instance of LocalService so clients can call public methods
return MediaPlayerService.this;
}
}
/**
* MediaPlayer callback methods
*/
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
//Invoked indicating buffering status of
//a media resource being streamed over the network.
}
#Override
public void onCompletion(MediaPlayer mp) {
//Invoked when playback of a media source has completed.
stopMedia();
removeNotification();
//stop the service
stopSelf();
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//Invoked when there has been an error during an asynchronous operation
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.d("MediaPlayer Error", "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.d("MediaPlayer Error", "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.d("MediaPlayer Error", "MEDIA ERROR UNKNOWN " + extra);
break;
}
return false;
}
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
//Invoked to communicate some info
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
//Invoked when the media source is ready for playback.
playMedia();
}
#Override
public void onSeekComplete(MediaPlayer mp) {
//Invoked indicating the completion of a seek operation.
}
#Override
public void onAudioFocusChange(int focusState) {
//Invoked when the audio focus of the system is updated.
switch (focusState) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
if (mediaPlayer == null) initMediaPlayer();
else if (!mediaPlayer.isPlaying()) mediaPlayer.start();
mediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
/**
* AudioFocus
*/
private boolean requestAudioFocus() {
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//Focus gained
return true;
}
//Could not gain focus
return false;
}
private boolean removeAudioFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
audioManager.abandonAudioFocus(this);
}
/**
* MediaPlayer actions
*/
private void initMediaPlayer() {
if (mediaPlayer == null)
mediaPlayer = new MediaPlayer();//new MediaPlayer instance
//Set up MediaPlayer event listeners
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
//Reset so that the MediaPlayer is not pointing to another data source
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
// Set the data source to the mediaFile location
mediaPlayer.setDataSource(activeAudio.getLocalData());
} catch (IOException e) {
e.printStackTrace();
stopSelf();
}
mediaPlayer.prepareAsync();
}
private void playMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
private void stopMedia() {
if (mediaPlayer == null) return;
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
private void pauseMedia() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
resumePosition = mediaPlayer.getCurrentPosition();
}
}
private void resumeMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(resumePosition);
mediaPlayer.start();
}
}
private void skipToNext() {
if (audioIndex == audioList.size() - 1) {
//if last in playlist
audioIndex = 0;
activeAudio = audioList.get(audioIndex);
} else {
//get next in playlist
activeAudio = audioList.get(++audioIndex);
}
//Update stored index
new StorageUtil(getApplicationContext()).storeAudioIndex(audioIndex);
stopMedia();
//reset mediaPlayer
mediaPlayer.reset();
initMediaPlayer();
}
private void skipToPrevious() {
if (audioIndex == 0) {
//if first in playlist
//set index to the last of audioList
audioIndex = audioList.size() - 1;
activeAudio = audioList.get(audioIndex);
} else {
//get previous in playlist
activeAudio = audioList.get(--audioIndex);
}
//Update stored index
new StorageUtil(getApplicationContext()).storeAudioIndex(audioIndex);
stopMedia();
//reset mediaPlayer
mediaPlayer.reset();
initMediaPlayer();
}
/**
* ACTION_AUDIO_BECOMING_NOISY -- change in audio outputs
*/
private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//pause audio on ACTION_AUDIO_BECOMING_NOISY
pauseMedia();
buildNotification(PlaybackStatus.PAUSED);
}
};
private void registerBecomingNoisyReceiver() {
//register after getting audio focus
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(becomingNoisyReceiver, intentFilter);
}
/**
* Handle PhoneState changes
*/
private void callStateListener() {
// Get the telephony manager
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//Starting listening for PhoneState changes
phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
//if at least one call exists or the phone is ringing
//pause the MediaPlayer
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer != null) {
pauseMedia();
ongoingCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone idle. Start playing.
if (mediaPlayer != null) {
if (ongoingCall) {
ongoingCall = false;
resumeMedia();
}
}
break;
}
}
};
// Register the listener with the telephony manager
// Listen for changes to the device call state.
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
}
/**
* MediaSession and Notification actions
*/
private void initMediaSession() throws RemoteException {
if (mediaSessionManager != null) return; //mediaSessionManager exists
mediaSessionManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
// Create a new MediaSession
mediaSession = new MediaSessionCompat(getApplicationContext(), "AudioPlayer");
//Get MediaSessions transport controls
transportControls = mediaSession.getController().getTransportControls();
//set MediaSession -> ready to receive media commands
mediaSession.setActive(true);
//indicate that the MediaSession handles transport control commands
// through its MediaSessionCompat.Callback.
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
//Set mediaSession's MetaData
updateMetaData();
// Attach Callback to receive MediaSession updates
mediaSession.setCallback(new MediaSessionCompat.Callback() {
// Implement callbacks
#Override
public void onPlay() {
super.onPlay();
resumeMedia();
buildNotification(PlaybackStatus.PLAYING);
}
#Override
public void onPause() {
super.onPause();
pauseMedia();
buildNotification(PlaybackStatus.PAUSED);
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
skipToNext();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
#Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
skipToPrevious();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
#Override
public void onStop() {
super.onStop();
removeNotification();
//Stop the service
stopSelf();
}
#Override
public void onSeekTo(long position) {
super.onSeekTo(position);
}
});
}
private void updateMetaData() {
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, activeAudio.getLocalArtist())
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, activeAudio.getLocalAlbum())
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, activeAudio.getLocalTitle())
.build());
}
private void buildNotification(PlaybackStatus playbackStatus) {
int notificationAction = android.R.drawable.ic_media_pause;//needs to be initialized
PendingIntent play_pauseAction = null;
//Build a new notification according to the current state of the MediaPlayer
if (playbackStatus == PlaybackStatus.PLAYING) {
notificationAction = android.R.drawable.ic_media_pause;
//create the pause action
play_pauseAction = playbackAction(1);
} else if (playbackStatus == PlaybackStatus.PAUSED) {
notificationAction = android.R.drawable.ic_media_play;
//create the play action
play_pauseAction = playbackAction(0);
}
// Create a new Notification
NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
// Hide the timestamp
.setShowWhen(false)
// Set the Notification style
.setStyle(new NotificationCompat.MediaStyle()
// Attach our MediaSession token
.setMediaSession(mediaSession.getSessionToken())
// Show our playback controls in the compat view
.setShowActionsInCompactView(0, 1, 2))
// Set the Notification color
.setColor(getResources().getColor(R.color.colorAccent))
// Set the large and small icons
.setSmallIcon(android.R.drawable.stat_sys_headset)
// Set Notification content information
.setContentText(activeAudio.getLocalArtist())
.setContentTitle(activeAudio.getLocalAlbum())
.setContentInfo(activeAudio.getLocalTitle())
// Add playback actions
.addAction(android.R.drawable.ic_media_previous, "previous", playbackAction(3))
.addAction(notificationAction, "pause", play_pauseAction)
.addAction(android.R.drawable.ic_media_next, "next", playbackAction(2));
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notificationBuilder.build());
}
private PendingIntent playbackAction(int actionNumber) {
Intent playbackAction = new Intent(this, MediaPlayerService.class);
switch (actionNumber) {
case 0:
// Play
playbackAction.setAction(ACTION_PLAY);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 1:
// Pause
playbackAction.setAction(ACTION_PAUSE);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 2:
// Next track
playbackAction.setAction(ACTION_NEXT);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 3:
// Previous track
playbackAction.setAction(ACTION_PREVIOUS);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
default:
break;
}
return null;
}
private void removeNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
private void handleIncomingActions(Intent playbackAction) {
if (playbackAction == null || playbackAction.getAction() == null) return;
String actionString = playbackAction.getAction();
if (actionString.equalsIgnoreCase(ACTION_PLAY)) {
transportControls.play();
} else if (actionString.equalsIgnoreCase(ACTION_PAUSE)) {
transportControls.pause();
} else if (actionString.equalsIgnoreCase(ACTION_NEXT)) {
transportControls.skipToNext();
} else if (actionString.equalsIgnoreCase(ACTION_PREVIOUS)) {
transportControls.skipToPrevious();
} else if (actionString.equalsIgnoreCase(ACTION_STOP)) {
transportControls.stop();
}
}
/**
* Play new Audio
*/
private BroadcastReceiver playNewAudio = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Get the new media index form SharedPreferences
audioIndex = new StorageUtil(getApplicationContext()).loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size()) {
//index is in a valid range
activeAudio = audioList.get(audioIndex);
} else {
stopSelf();
}
//A PLAY_NEW_AUDIO action received
//reset mediaPlayer to play the new Audio
stopMedia();
mediaPlayer.reset();
initMediaPlayer();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
};
private void register_playNewAudio() {
//Register playNewMedia receiver
IntentFilter filter = new IntentFilter(FragmentRight.Broadcast_PLAY_NEW_AUDIO);
registerReceiver(playNewAudio, filter);
}
And my Playlist fragment is like this:
public class FragmentRight extends Fragment {
public static final String Broadcast_PLAY_NEW_AUDIO = "com.example.anuj.musicmetest.PlayNewAudio";
private OnFragmentInteractionListener mListener;
ArrayList<Audio> localList;
TextView nameView;
private MediaPlayerService mediaPlayer;
boolean serviceBound = false;
public FragmentRight() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_right, container, false);
nameView = (TextView) rootView.findViewById(R.id.name1);
loadAudio();
RecyclerView recyclerView1 = (RecyclerView) rootView.findViewById(R.id.recycler_view1);
LocalListAdapter localListAdapteradapter = new LocalListAdapter(getActivity().getApplication(), localList);
recyclerView1.setAdapter(localListAdapteradapter);
recyclerView1.setLayoutManager(new LinearLayoutManager(getActivity().getApplication()));
recyclerView1.addOnItemTouchListener(new CustomTouchListener(getActivity(), new onItemClickListener() {
#Override
public void onClick(View view, int index) {
playAudio(index);
Intent intent = new Intent(getActivity(), MusicPlayer.class);
startActivity(intent);
}
}));
return rootView;
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
mediaPlayer = binder.getService();
serviceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
serviceBound = false;
}
};
private void playAudio(int audioIndex) {
//Check is service is active
if (!serviceBound) {
//Store Serializable audioList to SharedPreferences
StorageUtil storage = new StorageUtil(getActivity().getApplicationContext());
storage.storeAudio(localList);
storage.storeAudioIndex(audioIndex);
Intent playerIntent = new Intent(getActivity(), MediaPlayerService.class);
getActivity().startService(playerIntent);
getActivity().bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} else {
//Store the new audioIndex to SharedPreferences
StorageUtil storage = new StorageUtil(getActivity().getApplicationContext());
storage.storeAudioIndex(audioIndex);
Intent broadcastIntent = new Intent(Broadcast_PLAY_NEW_AUDIO);
getActivity().sendBroadcast(broadcastIntent);
}
}
private void loadAudio() {
ContentResolver contentResolver = getActivity().getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0";
String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
Cursor cursor = contentResolver.query(uri, null, selection, null, sortOrder);
if (cursor != null && cursor.getCount() > 0) {
localList = new ArrayList<>();
while (cursor.moveToNext()) {
String localData = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
String localTitle = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String localAlbum = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
String localArtist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
// Save to audioList
localList.add(new Audio(localData, localTitle, localAlbum, localArtist));
}
}
cursor.close();
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
#Override
public void onDestroy() {
super.onDestroy();
if (serviceBound) {
getContext().unbindService(serviceConnection);
//service is active
mediaPlayer.stopSelf();
}
}

How to play an audio from soundcloud in our app.?

Following program allows user to upload an audio from app to SoundCloud.But what if i need to play an audio from my account in soundcloud in my app?How to play an audio from soundcloud or from particular url of soundclous to in our app ?
public class Record extends Activity {
public static final String TAG = "soundcloud-intent-sharing-example";
private boolean mStarted;
private MediaRecorder mRecorder;
private File mArtwork;
private static boolean AAC_SUPPORTED = Build.VERSION.SDK_INT >= 10;
private static final int PICK_ARTWORK = 1;
private static final int SHARE_SOUND = 2;
private static final File FILES_PATH = new File(
Environment.getExternalStorageDirectory(),
"Android/data/com.soundcloud.android.examples/files");
private static final File RECORDING = new File(
FILES_PATH,
"demo-recording" + (AAC_SUPPORTED ? ".mp4" : "3gp"));
private static final Uri MARKET_URI = Uri.parse("market://details?id=com.soundcloud.android");
private static final int DIALOG_NOT_INSTALLED = 0;
// Replace with the client id of your registered app!
// see http://soundcloud.com/you/apps/
private static final String CLIENT_ID = "fecfc092de134a960dc48e53c044ee91";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Environment.MEDIA_MOUNTED.equals(
Environment.getExternalStorageState())) {
if (!FILES_PATH.mkdirs()) {
Log.w(TAG, "Could not create " + FILES_PATH);
}
} else {
Toast.makeText(this, R.string.need_external_storage, Toast.LENGTH_LONG).show();
finish();
}
setContentView(R.layout.record);
final Button record_btn = (Button) findViewById(R.id.record_btn);
final Button share_btn = (Button) findViewById(R.id.share_btn);
final Button play_btn = (Button) findViewById(R.id.play_btn);
final Button artwork_btn = (Button) findViewById(R.id.artwork_btn);
Record last = getLastNonConfigurationInstance();
if (last != null) {
mStarted = last.mStarted;
mRecorder = last.mRecorder;
mArtwork = last.mArtwork;
record_btn.setText(mStarted ? R.string.stop : R.string.record);
}
record_btn.setOnClickListener(new View.OnClickListener() {
public synchronized void onClick(View v) {
if (!mStarted) {
Toast.makeText(Record.this, R.string.recording, Toast.LENGTH_SHORT).show();
mStarted = true;
mRecorder = getRecorder(RECORDING, AAC_SUPPORTED);
mRecorder.start();
record_btn.setText(R.string.stop);
} else {
Toast.makeText(Record.this, R.string.recording_stopped, Toast.LENGTH_SHORT).show();
mRecorder.stop();
mRecorder.release();
mRecorder = null;
mStarted = false;
record_btn.setText(R.string.record);
share_btn.setEnabled(true);
play_btn.setEnabled(true);
artwork_btn.setEnabled(true);
}
}
});
play_btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
play_btn.setEnabled(false);
record_btn.setEnabled(false);
share_btn.setEnabled(false);
play(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
play_btn.setEnabled(true);
record_btn.setEnabled(true);
share_btn.setEnabled(true);
}
});
}
});
share_btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
shareSound();
}
});
artwork_btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), PICK_ARTWORK);
}
});
if (!isCompatibleSoundCloudInstalled(this)) {
showDialog(DIALOG_NOT_INSTALLED);
}
}
private void play(MediaPlayer.OnCompletionListener onCompletion) {
MediaPlayer player = new MediaPlayer();
try {
player.setDataSource(RECORDING.getAbsolutePath());
player.prepare();
player.setOnCompletionListener(onCompletion);
player.start();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// the actual sharing happens here
private void shareSound() {
Intent intent = new Intent("com.soundcloud.android.SHARE")
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(RECORDING))
// here you can set metadata for the track to be uploaded
.putExtra("com.soundcloud.android.extra.title", "SoundCloud Android Intent Demo upload")
.putExtra("com.soundcloud.android.extra.where", "Somewhere")
.putExtra("com.soundcloud.android.extra.description", "This is a demo track.")
.putExtra("com.soundcloud.android.extra.public", true)
.putExtra("com.soundcloud.android.extra.tags", new String[] {
"demo",
"post lolcat bluez",
"soundcloud:created-with-client-id="+CLIENT_ID
})
.putExtra("com.soundcloud.android.extra.genre", "Easy Listening")
.putExtra("com.soundcloud.android.extra.location", getLocation());
// attach artwork if user has picked one
if (mArtwork != null) {
intent.putExtra("com.soundcloud.android.extra.artwork", Uri.fromFile(mArtwork));
}
try {
startActivityForResult(intent, SHARE_SOUND);
} catch (ActivityNotFoundException notFound) {
// use doesn't have SoundCloud app installed, show a dialog box
showDialog(DIALOG_NOT_INSTALLED);
}
}
#Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SHARE_SOUND:
// callback gets executed when the SoundCloud app returns
if (resultCode == RESULT_OK) {
Toast.makeText(this, R.string.shared_ok, Toast.LENGTH_SHORT).show();
} else {
// canceled
Toast.makeText(this, R.string.shared_canceled, Toast.LENGTH_SHORT).show();
}
break;
case PICK_ARTWORK:
if (resultCode == RESULT_OK) {
mArtwork = getFromMediaUri(getContentResolver(), data.getData());
}
break;
}
}
private MediaRecorder getRecorder(File path, boolean useAAC) {
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
if (useAAC) {
recorder.setAudioSamplingRate(44100);
recorder.setAudioEncodingBitRate(96000);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
} else {
// older version of Android, use crappy sounding voice codec
recorder.setAudioSamplingRate(8000);
recorder.setAudioEncodingBitRate(12200);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
recorder.setOutputFile(path.getAbsolutePath());
try {
recorder.prepare();
} catch (IOException e) {
throw new RuntimeException(e);
}
return recorder;
}
// just get the last known location from the passive provider - not terribly
// accurate but it's a demo app.
private Location getLocation() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
}
#Override public Record getLastNonConfigurationInstance() {
return (Record) super.getLastNonConfigurationInstance();
}
#Override public Record onRetainNonConfigurationInstance() {
return this;
}
// Helper method to get file from a content uri
private static File getFromMediaUri(ContentResolver resolver, Uri uri) {
if ("file".equals(uri.getScheme())) {
return new File(uri.getPath());
} else if ("content".equals(uri.getScheme())) {
String[] filePathColumn = {MediaStore.MediaColumns.DATA};
Cursor cursor = resolver.query(uri, filePathColumn, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
return new File(filePath);
}
} finally {
cursor.close();
}
}
}
return null;
}
private static boolean isCompatibleSoundCloudInstalled(Context context) {
try {
PackageInfo info = context.getPackageManager()
.getPackageInfo("com.soundcloud.android",
PackageManager.GET_META_DATA);
// intent sharing only got introduced with version 22
return info != null && info.versionCode >= 22;
} catch (PackageManager.NameNotFoundException e) {
// not installed at all
return false;
}
}
#Override
protected Dialog onCreateDialog(int id, Bundle data) {
if (DIALOG_NOT_INSTALLED == id) {
return new AlertDialog.Builder(this)
.setTitle(R.string.sc_app_not_found)
.setMessage(R.string.sc_app_not_found_message)
.setPositiveButton(android.R.string.yes, new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent market = new Intent(Intent.ACTION_VIEW, MARKET_URI);
startActivity(market);
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
}).create();
} else {
return null;
}
}
}
knowing the url of the sound, you need to do the following:
resolve the URL in order to get the soundcloud API URL using Resolve endpoint
load the tracks API URL to get track representation in json or xml
initialise audio object and set the audio source to the value of stream_url property of track representation
The particular implementation varies depending on the libraries you use etc. But you'll definitely need to use HTTP requests, JSON parser and an audio object.

Chromecast - SIGN_IN_REQUIRED

Only a small portion of my users are getting this error and I can't for the life of me figure it out. I use GooglePlayServicesUtil.isGooglePlayServicesAvailable(downloadService) to test whether or not Play Services is available, and it always returns SUCCESS. I setup the channel to connect to the Chromecast, and everything works fine up until the point where I try to use RemoteMediaPlayer.load. The result is always SIGN_IN_REQUIRED for some users, with resolution: null. The status.toString() is Failed to load: Status{statusCode=SIGN_IN_REQUIRED, resolution=null}. I'm really not sure what I am supposed to with this or how to get rid of the error for my few users who are getting this.
I don't know what portion is related, so I am just posting my entire controller class:
public class ChromeCastController extends RemoteController {
private static final String TAG = ChromeCastController.class.getSimpleName();
private CastDevice castDevice;
private GoogleApiClient apiClient;
private ConnectionCallbacks connectionCallbacks;
private ConnectionFailedListener connectionFailedListener;
private Cast.Listener castClientListener;
private boolean applicationStarted = false;
private boolean waitingForReconnect = false;
private boolean error = false;
private boolean ignoreNextPaused = false;
private String sessionId;
private FileProxy proxy;
private String rootLocation;
private RemoteMediaPlayer mediaPlayer;
private double gain = 0.5;
public ChromeCastController(DownloadService downloadService, CastDevice castDevice) {
this.downloadService = downloadService;
this.castDevice = castDevice;
SharedPreferences prefs = Util.getPreferences(downloadService);
rootLocation = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
}
#Override
public void create(boolean playing, int seconds) {
downloadService.setPlayerState(PlayerState.PREPARING);
connectionCallbacks = new ConnectionCallbacks(playing, seconds);
connectionFailedListener = new ConnectionFailedListener();
castClientListener = new Cast.Listener() {
#Override
public void onApplicationStatusChanged() {
if (apiClient != null && apiClient.isConnected()) {
Log.i(TAG, "onApplicationStatusChanged: " + Cast.CastApi.getApplicationStatus(apiClient));
}
}
#Override
public void onVolumeChanged() {
if (apiClient != null && applicationStarted) {
try {
gain = Cast.CastApi.getVolume(apiClient);
} catch(Exception e) {
Log.w(TAG, "Failed to get volume");
}
}
}
#Override
public void onApplicationDisconnected(int errorCode) {
shutdownInternal();
}
};
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(castDevice, castClientListener);
apiClient = new GoogleApiClient.Builder(downloadService)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
apiClient.connect();
}
#Override
public void start() {
if(error) {
error = false;
Log.w(TAG, "Attempting to restart song");
startSong(downloadService.getCurrentPlaying(), true, 0);
return;
}
try {
mediaPlayer.play(apiClient);
} catch(Exception e) {
Log.e(TAG, "Failed to start");
}
}
#Override
public void stop() {
try {
mediaPlayer.pause(apiClient);
} catch(Exception e) {
Log.e(TAG, "Failed to pause");
}
}
#Override
public void shutdown() {
try {
if(mediaPlayer != null && !error) {
mediaPlayer.stop(apiClient);
}
} catch(Exception e) {
Log.e(TAG, "Failed to stop mediaPlayer", e);
}
try {
if(apiClient != null) {
Cast.CastApi.stopApplication(apiClient);
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace());
mediaPlayer = null;
applicationStarted = false;
}
} catch(Exception e) {
Log.e(TAG, "Failed to shutdown application", e);
}
if(apiClient != null && apiClient.isConnected()) {
apiClient.disconnect();
}
apiClient = null;
if(proxy != null) {
proxy.stop();
proxy = null;
}
}
private void shutdownInternal() {
// This will call this.shutdown() indirectly
downloadService.setRemoteEnabled(RemoteControlState.LOCAL, null);
}
#Override
public void updatePlaylist() {
if(downloadService.getCurrentPlaying() == null) {
startSong(null, false, 0);
}
}
#Override
public void changePosition(int seconds) {
try {
mediaPlayer.seek(apiClient, seconds * 1000L);
} catch(Exception e) {
Log.e(TAG, "FAiled to seek to " + seconds);
}
}
#Override
public void changeTrack(int index, DownloadFile song) {
startSong(song, true, 0);
}
#Override
public void setVolume(boolean up) {
double delta = up ? 0.1 : -0.1;
gain += delta;
gain = Math.max(gain, 0.0);
gain = Math.min(gain, 1.0);
getVolumeToast().setVolume((float) gain);
try {
Cast.CastApi.setVolume(apiClient, gain);
} catch(Exception e) {
Log.e(TAG, "Failed to the volume");
}
}
#Override
public int getRemotePosition() {
if(mediaPlayer != null) {
return (int) (mediaPlayer.getApproximateStreamPosition() / 1000L);
} else {
return 0;
}
}
#Override
public int getRemoteDuration() {
if(mediaPlayer != null) {
return (int) (mediaPlayer.getStreamDuration() / 1000L);
} else {
return 0;
}
}
void startSong(DownloadFile currentPlaying, boolean autoStart, int position) {
if(currentPlaying == null) {
try {
if (mediaPlayer != null && !error) {
mediaPlayer.stop(apiClient);
}
} catch(Exception e) {
// Just means it didn't need to be stopped
}
downloadService.setPlayerState(PlayerState.IDLE);
return;
}
downloadService.setPlayerState(PlayerState.PREPARING);
MusicDirectory.Entry song = currentPlaying.getSong();
try {
MusicService musicService = MusicServiceFactory.getMusicService(downloadService);
String url;
// Offline, use file proxy
if(Util.isOffline(downloadService) || song.getId().indexOf(rootLocation) != -1) {
if(proxy == null) {
proxy = new FileProxy(downloadService);
proxy.start();
}
url = proxy.getPublicAddress(song.getId());
} else {
if(proxy != null) {
proxy.stop();
proxy = null;
}
if(song.isVideo()) {
url = musicService.getHlsUrl(song.getId(), currentPlaying.getBitRate(), downloadService);
} else {
url = musicService.getMusicUrl(downloadService, song, currentPlaying.getBitRate());
}
url = fixURLs(url);
}
// Setup song/video information
MediaMetadata meta = new MediaMetadata(song.isVideo() ? MediaMetadata.MEDIA_TYPE_MOVIE : MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
meta.putString(MediaMetadata.KEY_TITLE, song.getTitle());
if(song.getTrack() != null) {
meta.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrack());
}
if(!song.isVideo()) {
meta.putString(MediaMetadata.KEY_ARTIST, song.getArtist());
meta.putString(MediaMetadata.KEY_ALBUM_ARTIST, song.getArtist());
meta.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbum());
String coverArt = "";
if(proxy == null) {
coverArt = musicService.getCoverArtUrl(downloadService, song);
coverArt = fixURLs(coverArt);
meta.addImage(new WebImage(Uri.parse(coverArt)));
} else {
File coverArtFile = FileUtil.getAlbumArtFile(downloadService, song);
if(coverArtFile != null && coverArtFile.exists()) {
coverArt = proxy.getPublicAddress(coverArtFile.getPath());
meta.addImage(new WebImage(Uri.parse(coverArt)));
}
}
}
String contentType;
if(song.isVideo()) {
contentType = "application/x-mpegURL";
}
else if(song.getTranscodedContentType() != null) {
contentType = song.getTranscodedContentType();
} else if(song.getContentType() != null) {
contentType = song.getContentType();
} else {
contentType = "audio/mpeg";
}
// Load it into a MediaInfo wrapper
MediaInfo mediaInfo = new MediaInfo.Builder(url)
.setContentType(contentType)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setMetadata(meta)
.build();
if(autoStart) {
ignoreNextPaused = true;
}
mediaPlayer.load(apiClient, mediaInfo, autoStart, position * 1000L).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(RemoteMediaPlayer.MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
// Handled in other handler
} else if(result.getStatus().getStatusCode() != ConnectionResult.SIGN_IN_REQUIRED) {
Log.e(TAG, "Failed to load: " + result.getStatus().toString());
failedLoad();
}
}
});
} catch (IllegalStateException e) {
Log.e(TAG, "Problem occurred with media during loading", e);
failedLoad();
} catch (Exception e) {
Log.e(TAG, "Problem opening media during loading", e);
failedLoad();
}
}
private String fixURLs(String url) {
// Only change to internal when using https
if(url.indexOf("https") != -1) {
SharedPreferences prefs = Util.getPreferences(downloadService);
int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
String externalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
String internalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance, null);
url = url.replace(internalUrl, externalUrl);
}
// Use separate profile for Chromecast so users can do ogg on phone, mp3 for CC
return url.replace(Constants.REST_CLIENT_ID, Constants.CHROMECAST_CLIENT_ID);
}
private void failedLoad() {
Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load));
downloadService.setPlayerState(PlayerState.STOPPED);
error = true;
}
private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
private boolean isPlaying;
private int position;
private ResultCallback<Cast.ApplicationConnectionResult> resultCallback;
ConnectionCallbacks(boolean isPlaying, int position) {
this.isPlaying = isPlaying;
this.position = position;
resultCallback = new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
sessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
applicationStarted = true;
setupChannel();
} else {
shutdownInternal();
}
}
};
}
#Override
public void onConnected(Bundle connectionHint) {
if (waitingForReconnect) {
Log.i(TAG, "Reconnecting");
reconnectApplication();
} else {
launchApplication();
}
}
#Override
public void onConnectionSuspended(int cause) {
Log.w(TAG, "Connection suspended");
isPlaying = downloadService.getPlayerState() == PlayerState.STARTED;
position = getRemotePosition();
waitingForReconnect = true;
}
void launchApplication() {
try {
Cast.CastApi.launchApplication(apiClient, CastCompat.APPLICATION_ID, false).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to launch application", e);
}
}
void reconnectApplication() {
try {
Cast.CastApi.joinApplication(apiClient, CastCompat.APPLICATION_ID, sessionId).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to reconnect application", e);
}
}
void setupChannel() {
if(!waitingForReconnect) {
mediaPlayer = new RemoteMediaPlayer();
mediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener() {
#Override
public void onStatusUpdated() {
MediaStatus mediaStatus = mediaPlayer.getMediaStatus();
if (mediaStatus == null) {
return;
}
switch (mediaStatus.getPlayerState()) {
case MediaStatus.PLAYER_STATE_PLAYING:
if (ignoreNextPaused) {
ignoreNextPaused = false;
}
downloadService.setPlayerState(PlayerState.STARTED);
break;
case MediaStatus.PLAYER_STATE_PAUSED:
if (!ignoreNextPaused) {
downloadService.setPlayerState(PlayerState.PAUSED);
}
break;
case MediaStatus.PLAYER_STATE_BUFFERING:
downloadService.setPlayerState(PlayerState.PREPARING);
break;
case MediaStatus.PLAYER_STATE_IDLE:
if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) {
downloadService.setPlayerState(PlayerState.COMPLETED);
downloadService.onSongCompleted();
} else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_INTERRUPTED) {
if (downloadService.getPlayerState() != PlayerState.PREPARING) {
downloadService.setPlayerState(PlayerState.PREPARING);
}
} else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_ERROR) {
Log.e(TAG, "Idle due to unknown error");
downloadService.setPlayerState(PlayerState.COMPLETED);
downloadService.next();
} else {
Log.w(TAG, "Idle reason: " + mediaStatus.getIdleReason());
downloadService.setPlayerState(PlayerState.IDLE);
}
break;
}
}
});
}
try {
Cast.CastApi.setMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace(), mediaPlayer);
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
if(!waitingForReconnect) {
DownloadFile currentPlaying = downloadService.getCurrentPlaying();
startSong(currentPlaying, isPlaying, position);
}
if(waitingForReconnect) {
waitingForReconnect = false;
}
}
}
private class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
#Override
public void onConnectionFailed(ConnectionResult result) {
shutdownInternal();
}
}
}
Edit for logs:
03-28 19:04:49.757 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: Chromecast Home Screen
03-28 19:04:52.280 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: null
03-28 19:04:54.162 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: Ready To Cast
03-28 19:05:05.194 6305-6305/github.daneren2005.dsub E/ChromeCastController﹕ Failed to load: Status{statusCode=SIGN_IN_REQUIRED, resolution=null}
It is strange that you are getting such status code at that time. What comes to mind is that the user may have not logged into his/her gmail account or something along those lines. Do you have the log file for us to take a look at to see if we can get more from the context? Also, to be sure, such user sees the application launched on the TV and only when it comes to loading a media that error is thrown?
The issue is due to using a Self Signed Certificate. I didn't realize the issue on my old phone because I had changed hosts and bought a normal certificate after switching phones. It would be nice if the SDK would through a useful error though. The one thrown makes you think that it is a problem with connecting to the Play Services SDK, and not a problem with the actual URL being used.

Categories

Resources