// Runs on a SECONDARY thread @Override public void processFrame(android.media.audiofx.Visualizer visualizer, boolean playing) { if (!lock.lockLowPriority()) return; try { if (transmitting) { // We use ignoreInput, because sampling 1024, 60 times a seconds, // is useless, as there are only 44100 or 48000 samples in one second if (ignoreInput == 0) { // WE MUST NEVER call any method from visualizer // while the player is not actually playing if (!playing) Arrays.fill(waveform, 0, 1024, (byte) 0x80); else visualizer.getWaveForm(waveform); } if (framesToSkip <= 0) { framesToSkip = framesToSkipOriginal; bt.getOutputStream() .write( waveform, 0, SimpleVisualizerJni.commonProcess(waveform, size | ignoreInput | dataType)); packetsSent++; } else { SimpleVisualizerJni.commonProcess(waveform, ignoreInput | dataType); framesToSkip--; } ignoreInput ^= IGNORE_INPUT; } int stateI = state.getAndSet(0); if (stateI != 0) { // Build and send a Player state message waveform[0] = StartOfHeading; waveform[1] = (byte) MessagePlayerState; waveform[3] = 0; int len = 0; len = writeByte(waveform, len, stateI & 3); len = writeByte(waveform, len, stateVolume); stateI = stateSongPosition; len = writeByte(waveform, len, stateI); len = writeByte(waveform, len, stateI >> 8); len = writeByte(waveform, len, stateI >> 16); len = writeByte(waveform, len, stateI >> 24); stateI = stateSongLength; len = writeByte(waveform, len, stateI); len = writeByte(waveform, len, stateI >> 8); len = writeByte(waveform, len, stateI >> 16); len = writeByte(waveform, len, stateI >> 24); waveform[2] = (byte) (len << 1); waveform[4 + len] = EndOfTransmission; bt.getOutputStream().write(waveform, 0, len + 5); packetsSent++; } } catch (IOException ex) { // Bluetooth error if (connected) MainHandler.sendMessage(this, MSG_BLUETOOTH_RXTX_ERROR); } catch (Throwable ex) { ex.printStackTrace(); } finally { lock.releaseLowPriority(); } }
public BluetoothVisualizerControllerJni( ActivityHost activity, boolean startTransmissionOnConnection) { waveform = new byte[Visualizer.CAPTURE_SIZE]; lock = new SlimLock(); state = new AtomicInteger(); this.startTransmissionOnConnection = startTransmissionOnConnection; lastPlayerCommandTime = (int) SystemClock.uptimeMillis(); ignoreInput = 0; Player.bluetoothVisualizerLastErrorMessage = 0; Player.bluetoothVisualizerState = Player.BLUETOOTH_VISUALIZER_STATE_CONNECTING; bt = new BluetoothConnectionManager(this); final int err = bt.showDialogAndScan(activity); if (err != BluetoothConnectionManager.OK) onBluetoothError(bt, err); else BackgroundActivityMonitor.start(activity); }
public void destroy() { if (waveform != null) { version++; connected = false; transmitting = false; Player.bluetoothVisualizerState = Player.BLUETOOTH_VISUALIZER_STATE_INITIAL; lock.lockHighPriority(); try { waveform = null; if (bt != null) { bt.destroy(); bt = null; } } finally { lock.releaseHighPriority(); } if (fxVisualizer != null) { fxVisualizer.destroy(); fxVisualizer = null; } Player.stopBluetoothVisualizer(); BackgroundActivityMonitor.bluetoothEnded(); } }
@Override public void run() { final int myVersion = version; try { final InputStream inputStream = bt.getInputStream(); int state = 0, payloadLength = 0, payload = 0, currentMessage = 0; while (connected && myVersion == version) { final int data = inputStream.read(); if (data == StartOfHeading) { // Restart the state machine state &= (~(FlagEscape | FlagState)); continue; } switch ((state & FlagState)) { case 0: // This byte should be the message type switch (data) { case MessageStartBinTransmission: case MessageStopBinTransmission: case MessagePlayerCommand: // Take the state machine to its next state currentMessage = data; state++; continue; default: // Take the state machine to its error state state |= FlagState; continue; } case 1: // This should be payload length's first byte // (bits 0 - 6 left shifted by 1) if ((data & 0x01) != 0) { // Take the state machine to its error state state |= FlagState; } else { payloadLength = data >> 1; // Take the state machine to its next state state++; } continue; case 2: // This should be payload length's second byte // (bits 7 - 13 left shifted by 1) if ((data & 0x01) != 0) { // Take the state machine to its error state state |= FlagState; } else { payloadLength |= (data << 6); if (currentMessage == MessageStopBinTransmission) { if (payloadLength != 0) { // Take the state machine to its error state state |= FlagState; continue; } // Skip two states as this message has no payload state += 2; } else { if (payloadLength != 1) { if (currentMessage != MessagePlayerCommand || payloadLength != 2) { // Take the state machine to its error state state |= FlagState; continue; } } // Take the state machine to its next state state++; payload = 0; } } continue; case 3: // We are receiving the payload if (data == Escape) { // Until this date, the only payloads which are // valid for reception do not include escapable bytes... // Take the state machine to its error state state |= FlagState; continue; } if (currentMessage == MessagePlayerCommand) { payload = (payload << 8) | data; payloadLength--; // Keep the machine in state 3 if (payloadLength > 0) continue; } else { payload = data; } // For now, the only payload received is 1 byte long state++; continue; case 4: // Take the state machine to its error state state |= FlagState; // Sanity check: data should be EoT if (data == EndOfTransmission) // Message correctly received MainHandler.sendMessage(this, MSG_PLAYER_COMMAND, currentMessage, payload); } } } catch (IOException ex) { // Bluetooth error if (connected) MainHandler.sendMessage(this, MSG_BLUETOOTH_RXTX_ERROR); } catch (Throwable ex) { ex.printStackTrace(); } }