I am using the google stun server in both android and iOS. For data communication using the firebase. I am able to connect android to android video call and iOS to iOS video call. But while connect the android to iOS and iOS to android it show the remote video as black screen
iOS code
let configuration = RTCConfiguration()
configuration.iceServers = [
RTCIceServer(urlStrings: [
"stun:stun1.l.google.com:19302", "stun:stun2.l.google.com:19302"
])
]
private let factory: RTCPeerConnectionFactory = {
let videoEncoderFactory = RTCSimluatorVideoEncoderFactory()
let videoDecoderFactory = RTCSimulatorVideoDecoderFactory()
print(videoEncoderFactory)
videoEncoderFactory.preferredCodec = RTCVideoCodecInfo(name: kRTCVideoCodecVp8Name)
return RTCPeerConnectionFactory(encoderFactory: videoEncoderFactory, decoderFactory: videoDecoderFactory)
}()
videoSource!.adaptOutputFormat(toWidth: 1280, height: 720, fps: 30)
videoCapturer = RTCCameraVideoCapturer(delegate: videoSource!)
localVideoTrack = factory.videoTrack(with: videoSource!, trackId: "local_track")
localAudioTrack = factory.audioTrack(with: audioSource, trackId: "local_track" + "_audio")
localAudioTrack.isEnabled = true
// audioSource.volume = 1
super.init()
let constraints = RTCMediaConstraints(mandatoryConstraints: nil,
optionalConstraints: ["DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue])
peerConnection = factory.peerConnection(with: configuration, constraints: constraints, delegate: self)
peerConnection?.add(localVideoTrack, streamIds: ["local_track"])
peerConnection?.add(localAudioTrack,streamIds: ["local_track"])
remoteVideoTrack = peerConnection?.transceivers.first { $0.mediaType == .video }?.receiver.track as? RTCVideoTrack
Android code
private val iceServer = listOf(
PeerConnection.IceServer.builder("stun:stun.l.google.com:19302")
.createIceServer(),
PeerConnection.IceServer.builder("stun:stun2.l.google.com:19302")
.createIceServer()
)
private fun initPeerConnectionFactory(context: Application) {
val options = PeerConnectionFactory.InitializationOptions.builder(context)
.setEnableInternalTracer(true)
.setFieldTrials("WebRTC-H264HighProfile/Enabled/")
.createInitializationOptions()
PeerConnectionFactory.initialize(options)
}
private fun buildPeerConnectionFactory(): PeerConnectionFactory {
return PeerConnectionFactory
.builder()
.setVideoDecoderFactory(DefaultVideoDecoderFactory(rootEglBase.eglBaseContext))
.setVideoEncoderFactory(DefaultVideoEncoderFactory(rootEglBase.eglBaseContext, true, true))
.setOptions(PeerConnectionFactory.Options().apply {
disableEncryption = false
disableNetworkMonitor = true
})
.createPeerConnectionFactory()
}
fun startLocalVideoCapture(localVideoOutput: SurfaceViewRenderer) {
val surfaceTextureHelper = SurfaceTextureHelper.create(Thread.currentThread().name, rootEglBase.eglBaseContext)
(videoCapturer as VideoCapturer).initialize(surfaceTextureHelper, localVideoOutput.context, localVideoSource.capturerObserver)
videoCapturer.startCapture(1280, 720, 60)
localAudioTrack = peerConnectionFactory.createAudioTrack(LOCAL_TRACK_ID + "_audio", audioSource);
localVideoTrack = peerConnectionFactory.createVideoTrack(LOCAL_TRACK_ID, localVideoSource)
localVideoTrack?.addSink(localVideoOutput)
val localStream = peerConnectionFactory.createLocalMediaStream(LOCAL_STREAM_ID)
localStream.addTrack(localVideoTrack)
localStream.addTrack(localAudioTrack)
peerConnection?.addStream(localStream)
}
I need help for connecting android and ios without black screen in remote video
Android:
v=0o=- 6563448285196734461 2 IN IP4 127.0.0.1s=-t=0 0a=group:BUNDLE audio videoa=msid-semantic: WMSm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 100 101 127 124 125c=IN IP4 0.0.0.0a=rtcp:9 IN IP4 0.0.0.0a=ice-ufrag:I69Ta=ice-pwd:RY4fL2nYEJVHJ1vDc7fsws0qa=ice-options:trickle renominationa=fingerprint:sha-256 91:33:FC:D0:9C:BD:FE:A8:F4:7D:8F:6E:1F:71:05:4F:5B:F3:A0:DA:86:14:8A:CA:29:F0:45:AB:88:02:EE:50a=setup:activea=mid:audioa=extmap:14 urn:ietf:params:rtp-hdrext:toffseta=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-timea=extmap:13 urn:3gpp:video-orientationa=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delaya=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-typea=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timinga=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-spacea=recvonlya=rtcp-muxa=rtcp-rsizea=rtpmap:96 VP8/90000a=rtcp-fb:96 goog-remba=rtcp-fb:96 transport-cca=rtcp-fb:96 ccm fira=rtcp-fb:96 nacka=rtcp-fb:96 nack plia=rtpmap:97 rtx/90000a=fmtp:97 apt=96a=rtpmap:98 H264/90000a=rtcp-fb:98 goog-remba=rtcp-fb:98 transport-cca=rtcp-fb:98 ccm fira=rtcp-fb:98 nacka=rtcp-fb:98 nack plia=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1fa=rtpmap:100 H264/90000a=rtcp-fb:100 goog-remba=rtcp-fb:100 transport-cca=rtcp-fb:100 ccm fira=rtcp-fb:100 nacka=rtcp-fb:100 nack plia=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01fa=rtpmap:101 rtx/90000a=fmtp:101 apt=100a=rtpmap:127 red/90000a=rtpmap:124 rtx/90000a=fmtp:124 apt=127a=rtpmap:125 ulpfec/90000m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126c=IN IP4 0.0.0.0a=rtcp:9 IN IP4 0.0.0.0a=ice-ufrag:I69Ta=ice-pwd:RY4fL2nYEJVHJ1vDc7fsws0qa=ice-options:trickle renominationa=fingerprint:sha-256 91:33:FC:D0:9C:BD:FE:A8:F4:7D:8F:6E:1F:71:05:4F:5B:F3:A0:DA:86:14:8A:CA:29:F0:45:AB:88:02:EE:50a=setup:activea=mid:videoa=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-levela=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-timea=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01a=recvonlya=rtcp-muxa=rtpmap:111 opus/48000/2a=rtcp-fb:111 transport-cca=fmtp:111 minptime=10;useinbandfec=1a=rtpmap:103 ISAC/16000a=rtpmap:104 ISAC/32000a=rtpmap:9 G722/8000a=rtpmap:102 ILBC/8000a=rtpmap:0 PCMU/8000a=rtpmap:8 PCMA/8000a=rtpmap:106 CN/32000a=rtpmap:105 CN/16000a=rtpmap:13 CN/8000a=rtpmap:110 telephone-event/48000a=rtpmap:112 telephone-event/32000a=rtpmap:113 telephone-event/16000a=rtpmap:126 telephone-event/8000
iOS
v=0o=- 8886095848359872555 2 IN IP4 127.0.0.1s=-t=0 0a=group:BUNDLE audio videoa=msid-semantic: WMS local_trackm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 124 125c=IN IP4 0.0.0.0a=rtcp:9 IN IP4 0.0.0.0a=ice-ufrag:1BBja=ice-pwd:uaFw/ANPPPKHdZmf+qr31phba=ice-options:trickle renominationa=fingerprint:sha-256 1B:D0:0D:16:73:CD:FF:B9:F5:C3:8E:86:3D:83:DF:5D:3D:40:86:B1:67:D5:D3:9D:A4:92:AA:0F:C6:09:AE:ECa=setup:actpassa=mid:audioa=extmap:14 urn:ietf:params:rtp-hdrext:toffseta=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-timea=extmap:13 urn:3gpp:video-orientationa=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delaya=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-typea=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timinga=extmap:8 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-spacea=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mida=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-ida=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-ida=sendrecva=msid:local_track local_tracka=rtcp-muxa=rtcp-rsizea=rtpmap:96 VP8/90000a=rtcp-fb:96 goog-remba=rtcp-fb:96 transport-cca=rtcp-fb:96 ccm fira=rtcp-fb:96 nacka=rtcp-fb:96 nack plia=rtpmap:97 rtx/90000a=fmtp:97 apt=96a=rtpmap:98 H264/90000a=rtcp-fb:98 goog-remba=rtcp-fb:98 transport-cca=rtcp-fb:98 ccm fira=rtcp-fb:98 nacka=rtcp-fb:98 nack plia=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1fa=rtpmap:99 rtx/90000a=fmtp:99 apt=98a=rtpmap:100 H264/90000a=rtcp-fb:100 goog-remba=rtcp-fb:100 transport-cca=rtcp-fb:100 ccm fira=rtcp-fb:100 nacka=rtcp-fb:100 nack plia=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01fa=rtpmap:101 rtx/90000a=fmtp:101 apt=100a=rtpmap:127 red/90000a=rtpmap:124 rtx/90000a=fmtp:124 apt=127a=rtpmap:125 ulpfec/90000a=ssrc-group:FID 1956454411 1435441277a=ssrc:1956454411 cname:BnVPai9gO/G5EEuLa=ssrc:1956454411 msid:local_track local_tracka=ssrc:1956454411 mslabel:local_tracka=ssrc:1956454411 label:local_tracka=ssrc:1435441277 cname:BnVPai9gO/G5EEuLa=ssrc:1435441277 msid:local_track local_tracka=ssrc:1435441277 mslabel:local_tracka=ssrc:1435441277 label:local_trackm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126c=IN IP4 0.0.0.0a=rtcp:9 IN IP4 0.0.0.0a=ice-ufrag:1BBja=ice-pwd:uaFw/ANPPPKHdZmf+qr31phba=ice-options:trickle renominationa=fingerprint:sha-256 1B:D0:0D:16:73:CD:FF:B9:F5:C3:8E:86:3D:83:DF:5D:3D:40:86:B1:67:D5:D3:9D:A4:92:AA:0F:C6:09:AE:ECa=setup:actpassa=mid:videoa=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-levela=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-timea=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mida=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-ida=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-ida=sendrecva=msid:local_track local_track_audioa=rtcp-muxa=rtpmap:111 opus/48000/2a=rtcp-fb:111 transport-cca=fmtp:111 minptime=10;useinbandfec=1a=rtpmap:103 ISAC/16000a=rtpmap:104 ISAC/32000a=rtpmap:9 G722/8000a=rtpmap:102 ILBC/8000a=rtpmap:0 PCMU/8000a=rtpmap:8 PCMA/8000a=rtpmap:106 CN/32000a=rtpmap:105 CN/16000a=rtpmap:13 CN/8000a=rtpmap:110 telephone-event/48000a=rtpmap:112 telephone-event/32000a=rtpmap:113 telephone-event/16000a=rtpmap:126 telephone-event/8000a=ssrc:2967951894 cname:BnVPai9gO/G5EEuLa=ssrc:2967951894 msid:local_track local_track_audioa=ssrc:2967951894 mslabel:local_tracka=ssrc:2967951894 label:local_track_audio
I have a application that I got froma freelancing team that uses classical Bluetooth in data exchange. I am in the process of switching it from classical Bluetooth to BLE.
Now there are different fragments each with their own viewmodels, viewmodel factories and their repositories that acts as an intermediary between the viewmodel and the DataStore class that hosts the data.
I was following a guide and what I achieved so far is scanning for BLE devices and connecting to them to display the characteristics and their properties (Readable, Writable, Indicatable, Notifiable). I have an activity that scans for devices and then upon selecting a device it goes to another activity, connects to the device and displays the characteristics.
Different Parameters are symbolized with codes likes these:
enum class ReadRequestCodes(val value:String) {
KEY_ADDRESS ("08 00 00 00 20 30 05 11 00 00 00 00 00"),
TOOL_ADDRESS ("08 00 00 00 20 30 05 27 00 00 00 00 00"),
RPM_THRESHOLD("08 00 00 00 20 30 05 13 00 00 00 00 00"),
BACKLASH ("08 00 00 00 20 30 05 22 00 00 00 00 00"),
POWER_SRC_TYPE ("08 00 00 00 20 30 05 26 00 00 00 00 00"),
BATTERY1_PERCENTAGE("08 00 00 00 20 30 11 00 00 00 00 00 00"),
BATTERY2_PERCENTAGE("08 00 00 00 20 30 12 00 00 00 00 00 00"),
HOME_POSITION ("08 00 00 00 20 30 05 15 00 00 00 00 00"),
BYPASS_POSITION ("08 00 00 00 20 30 05 17 00 00 00 00 00"),
HC_POSITION ("08 00 00 00 20 30 05 19 00 00 00 00 00"),
ISOLATION_POSITION("08 00 00 00 20 30 05 1B 00 00 00 00 00"),
PRESSURE_SENSOR_GAIN("08 00 00 00 20 30 05 2B 00 00 00 00 00"),
PRESSURE_SENSOR_OFFSET("08 00 00 00 20 30 05 2C 00 00 00 00 00"),
PRESSURE_SENSOR_RANGE("08 00 00 00 20 30 05 2A 00 00 00 00 00"),
PRESSURE_SENSOR_EXCITATION("08 00 00 00 20 30 05 29 00 00 00 00 00"),
PRESSURE_SENSOR_SERIAL("08 00 00 00 20 30 05 2D 00 00 00 00 00"),
}
there are enums for read requests, write commands, read response.
Now in the fragments previously mentioned there are buttons that are supposed to initiate a request, basically you click and it requests the parameter that corresponds to one of the codes like in the snippet and acquires the value from the device I'm connected to. In other cases I type in data and send it to the device, and the parameter is symbolized with a code similar to the one in the snippet but for write commands.
Now the issue here is HOW to do I exchange data? The code below is form my call back function when I connect to a device:
private val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
val deviceAddress = gatt.device.address
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Timber.w("onConnectionStateChange: connected to $deviceAddress")
deviceGattMap[gatt.device] = gatt
Handler(Looper.getMainLooper()).post {
gatt.discoverServices()
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Timber.e("onConnectionStateChange: disconnected from $deviceAddress")
teardownConnection(gatt.device)
}
} else {
Timber.e("onConnectionStateChange: status $status encountered for $deviceAddress!")
if (pendingOperation is Connect) {
signalEndOfOperation()
}
teardownConnection(gatt.device)
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
with(gatt) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Timber.w("Discovered ${services.size} services for ${device.address}.")
printGattTable()
requestMtu(device, GATT_MAX_MTU_SIZE)
listeners.forEach { it.get()?.onConnectionSetupComplete?.invoke(this) }
} else {
Timber.e("Service discovery failed due to status $status")
teardownConnection(gatt.device)
}
}
if (pendingOperation is Connect) {
signalEndOfOperation()
}
}
override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
Timber.w("ATT MTU changed to $mtu, success: ${status == BluetoothGatt.GATT_SUCCESS}")
listeners.forEach { it.get()?.onMtuChanged?.invoke(gatt.device, mtu) }
if (pendingOperation is MtuRequest) {
signalEndOfOperation()
}
}
override fun onCharacteristicRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
with(characteristic) {
when (status) {
BluetoothGatt.GATT_SUCCESS -> {
Timber.i("Read characteristic $uuid | value: ${value.toHexString()}")
listeners.forEach {
it.get()?.onCharacteristicRead?.invoke(
gatt.device,
this
)
}
}
BluetoothGatt.GATT_READ_NOT_PERMITTED -> {
Timber.e("Read not permitted for $uuid!")
}
else -> {
Timber.e("Characteristic read failed for $uuid, error: $status")
}
}
}
if (pendingOperation is CharacteristicRead) {
signalEndOfOperation()
}
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
with(characteristic) {
when (status) {
BluetoothGatt.GATT_SUCCESS -> {
Timber.i("Wrote to characteristic $uuid | value: ${value.toHexString()}")
listeners.forEach {
it.get()?.onCharacteristicWrite?.invoke(
gatt.device,
this
)
}
}
BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> {
Timber.e("Write not permitted for $uuid!")
}
else -> {
Timber.e("Characteristic write failed for $uuid, error: $status")
}
}
}
if (pendingOperation is CharacteristicWrite) {
signalEndOfOperation()
}
}
override fun onCharacteristicChanged(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
with(characteristic) {
Timber.i("Characteristic $uuid changed | value: ${value.toHexString()}")
listeners.forEach { it.get()?.onCharacteristicChanged?.invoke(gatt.device, this) }
}
}
override fun onDescriptorRead(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
with(descriptor) {
when (status) {
BluetoothGatt.GATT_SUCCESS -> {
Timber.i("Read descriptor $uuid | value: ${value.toHexString()}")
listeners.forEach { it.get()?.onDescriptorRead?.invoke(gatt.device, this) }
}
BluetoothGatt.GATT_READ_NOT_PERMITTED -> {
Timber.e("Read not permitted for $uuid!")
}
else -> {
Timber.e("Descriptor read failed for $uuid, error: $status")
}
}
}
if (pendingOperation is DescriptorRead) {
signalEndOfOperation()
}
}
override fun onDescriptorWrite(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
with(descriptor) {
when (status) {
BluetoothGatt.GATT_SUCCESS -> {
Timber.i("Wrote to descriptor $uuid | value: ${value.toHexString()}")
if (isCccd()) {
onCccdWrite(gatt, value, characteristic)
} else {
listeners.forEach {
it.get()?.onDescriptorWrite?.invoke(
gatt.device,
this
)
}
}
}
BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> {
Timber.e("Write not permitted for $uuid!")
}
else -> {
Timber.e("Descriptor write failed for $uuid, error: $status")
}
}
}
if (descriptor.isCccd() &&
(pendingOperation is EnableNotifications || pendingOperation is DisableNotifications)
) {
signalEndOfOperation()
} else if (!descriptor.isCccd() && pendingOperation is DescriptorWrite) {
signalEndOfOperation()
}
}
private fun onCccdWrite(
gatt: BluetoothGatt,
value: ByteArray,
characteristic: BluetoothGattCharacteristic
) {
val charUuid = characteristic.uuid
val notificationsEnabled =
value.contentEquals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) ||
value.contentEquals(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)
val notificationsDisabled =
value.contentEquals(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)
when {
notificationsEnabled -> {
Timber.w("Notifications or indications ENABLED on $charUuid")
listeners.forEach {
it.get()?.onNotificationsEnabled?.invoke(
gatt.device,
characteristic
)
}
}
notificationsDisabled -> {
Timber.w("Notifications or indications DISABLED on $charUuid")
listeners.forEach {
it.get()?.onNotificationsDisabled?.invoke(
gatt.device,
characteristic
)
}
}
else -> {
Timber.e("Unexpected value ${value.toHexString()} on CCCD of $charUuid")
}
}
}
}
This was from the activity I displayed the characteristics in:
private val connectionEventListener by lazy {
ConnectionEventListener().apply {
onDisconnect = {
runOnUiThread {
alert {
title = "Disconnected"
message = "Disconnected from device."
positiveButton("OK") { onBackPressed() }
}.show()
}
}
onCharacteristicRead = { _, characteristic ->
Timber.i("Read from ${characteristic.uuid}: ${characteristic.value.toHexString()}")
}
onCharacteristicWrite = { _, characteristic ->
Timber.i("Wrote to: ${characteristic.uuid}")
}
onMtuChanged = { _, mtu ->
Timber.i("MTU updated to: $mtu")
}
onCharacteristicChanged = { _, characteristic ->
Timber.i("Value changed on ${characteristic.uuid}: ${characteristic.value.toHexString()}")
}
onNotificationsEnabled = { _, characteristic ->
Timber.i("Notify enabled on: ${characteristic.uuid}")
notifyingCharacteristics.add(characteristic.uuid)
}
onNotificationsDisabled = { _, characteristic ->
Timber.i("Notify disabled on: ${characteristic.uuid}")
notifyingCharacteristics.remove(characteristic.uuid)
}
}
}
I don't know what else I need to post here but I can edit if the need arises. The point here I am stuck and don't know how to proceed. If I am able to connect to the BLE device and display its characteristics and all that, how do I get it to send me data or send to it data? How do I go from here?
I am facing a problem with coding my first Android-App.
I want to build the login-system of the app around my existing webserver/webinterface.
I am using the Fuel-Library, and as far as I can tell, the GET Requests are working fine.
The problem is the response. When I print it out, everything is see is some information about the request itself, but the printed echo from PHP isn't showing up anywhere.
Response printed out:
I/System.out: <-- 200 https://...hidden :)
I/System.out: Response : OK
Length : -1
Body : test
Headers : (11)
Connection : Keep-Alive
Date : Mon, 30 Mar 2020 18:06:39 GMT
X-Android-Selected-Protocol : http/1.1
Server : Apache
X-Powered-By : PHP/7.3.5, PleskLin
Content-Type : text/html; charset=UTF-8
X-Android-Received-Millis : 1585591597000
Vary : Accept-Encoding
X-Android-Response-Source : NETWORK 200
X-Android-Sent-Millis : 1585591596960
Keep-Alive : timeout=5, max=100
The same is happening with POST Requests.
Here is my Kotlin-Code:
val url = "https://myserver.com/testlogin.php?username=".plus(username.toString()).plus("&password=").plus(password.toString())
url.httpGet().responseString{
request, response, result ->
Toast.makeText(this#MainActivity, result.toString(), Toast.LENGTH_LONG).show()
}
And the PHP Code on the Webserver:
<?php $username = $_GET["username"]; $password = $_GET["password"]; echo $username; ?>
I am searching for more than 7 hours now. send help
Try this
url.httpGet().responseString { request, response, result ->
when (result) {
is Result.Failure -> {
val ex = result.getException()
println(ex)
}
is Result.Success -> {
val data = result.get()
println(data)
}
}
}
Official documentation
I just found the problem:
val data = result.get() println(data)
prints the response string of the php file.
I get this following error when I'm trying to make a HTTP call with okhttp:
W/System.err: java.io.EOFException: source exhausted prematurely
W/System.err: at okio.InflaterSource.read(InflaterSource.java:83)
W/System.err: at okio.GzipSource.read(GzipSource.java:80)
W/System.err: at okio.Buffer.writeAll(Buffer.java:1135)
W/System.err: at okio.RealBufferedSource.readString(RealBufferedSource.java:199)
W/System.err: at okhttp3.ResponseBody.string(ResponseBody.java:176)
W/System.err: at com.ethanwang.andplay.OKHttpTaskTag.doInBackground(OKHttpTaskTag.java:41)
W/System.err: at com.ethanwang.andplay.OKHttpTaskTag.doInBackground(OKHttpTaskTag.java:20)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:295)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err: at java.lang.Thread.run(Thread.java:818)
I was only able to find this related issue: https://github.com/square/okhttp/issues/2193 but I have made sure that Content-Length is the correct length of the response body. Here is my logged okhttp request and response:
Request:
I/System.out: INFO: Sending request http://test.essaybot.com/msg/tag_search on Connection{test.essaybot.com:80, proxy=DIRECT# hostAddress=test.essaybot.com/34.208.145.50:80 cipherSuite=none protocol=http/1.1}
I/System.out: Content-Type: application/x-www-form-urlencoded
I/System.out: Content-Length: 33
I/System.out: Host: test.essaybot.com
I/System.out: Connection: Keep-Alive
I/System.out: Accept-Encoding: gzip
I/System.out: User-Agent: okhttp/3.11.0
Response:
I/System.out: INFO: Received response for http://test.essaybot.com/msg/tag_search in 62.2ms
I/System.out: Cache-Control: no-cache
I/System.out: Content-Encoding: gzip
I/System.out: Content-Length: 139
I/System.out: Content-Type: application/json
I/System.out: Set-Cookie: PHP_SESSION=0Q4rZJplDjrUNB4ZbWAG; Path=/; Max-Age=2592000
I/System.out: Set-Cookie: VISITOR_ID=65xGr53M1xM0waK8; Path=/; Max-Age=31536000
I/System.out: Date: Wed, 29 Aug 2018 20:45:06 GMT
I/System.out: INFO: Received response body bytes:
I/System.out: [31, -117, 8, 0, 0, 0, 0, 0, 0, -1, 44, -51, 65, 10, -62, 64, 12, 5, -48, -85, 72, -42, 93, -72, -18, -50, -91, 103, 16, -111, -23, 52, -83, 31, 66, -90, 100, 50, -94, -120, 119, -105, 116, -70, 9, 47, -16, -109, -1, 37, 54, 123, 104, -95, -15, 60, -112, 113, 109, -30, 52, -34, -24, 50, -65, 88, -67, 25, -45, 16, 70, -34, 97, 30, 115, 49, -28, 20, -128, 9, -108, 107, 80, -33, 96, -1, -12, 12, 22, 100, 36, 57, 93, -43, 89, 4, 43, 107, -65, -34, -74, 61, 58, -49, -56, -114, -94, -31, 86, -35, -110, -32, -8, 54, -23, 20, 88, -95, 107, -81, 101, 115, -44, 99, -109, 92, -98, 69, 66, 21, -119, -18, -65, 63, 0, 0, 0, -1, -1]
I/System.out: With length: 139
The server works perfectly fine with our web and iOS ends. It also worked fine with android until about two months ago, when it suddenly stopped working with no network changes. What else could cause this error?
-------------------------------------- updated --------------------------------------
It seems like the data in buffer is readable since from the debugger above there is readable text ([size=185 text={"err_no":0,"result":["Adventure","Advice","Art","Africa","Airliā¦]) annotated after the buffer variable. Also, the data from the debugger is different from the logged data:
data = {byte[8192]#4418}
0 = 123
1 = 34
2 = 101
3 = 114
4 = 114
5 = 95
6 = 110
7 = 111
8 = 34
9 = 58
10 = 48
11 = 44
12 = 34
13 = 114
14 = 101
15 = 115
16 = 117
17 = 108
18 = 116
19 = 34
20 = 58
21 = 91
22 = 34
23 = 65
24 = 100
25 = 118
26 = 101
27 = 110
28 = 116
29 = 117
30 = 114
31 = 101
32 = 34
33 = 44
34 = 34
35 = 65
36 = 100
37 = 118
38 = 105
39 = 99
40 = 101
41 = 34
42 = 44
43 = 34
44 = 65
45 = 114
46 = 116
47 = 34
48 = 44
49 = 34
50 = 65
51 = 102
52 = 114
53 = 105
54 = 99
55 = 97
56 = 34
57 = 44
58 = 34
59 = 65
60 = 105
61 = 114
62 = 108
63 = 105
64 = 110
65 = 101
66 = 115
67 = 34
68 = 44
69 = 34
70 = 65
71 = 110
72 = 120
73 = 105
74 = 101
75 = 116
76 = 121
77 = 34
78 = 44
79 = 34
80 = 65
81 = 114
82 = 116
83 = 105
84 = 102
85 = 105
86 = 99
87 = 105
88 = 97
89 = 108
90 = 32
91 = 73
92 = 110
93 = 116
94 = 101
95 = 108
96 = 108
97 = 105
98 = 103
99 = 101
100 = 110
101 = 99
102 = 101
103 = 34
104 = 44
105 = 34
106 = 65
107 = 112
108 = 112
109 = 115
110 = 34
111 = 44
112 = 34
113 = 65
114 = 100
115 = 100
116 = 105
117 = 99
118 = 116
119 = 105
120 = 111
121 = 110
122 = 34
123 = 44
124 = 34
125 = 65
126 = 117
127 = 115
128 = 116
129 = 114
130 = 97
131 = 108
132 = 105
133 = 97
134 = 34
135 = 44
136 = 34
137 = 65
138 = 105
139 = 114
140 = 98
141 = 110
142 = 98
143 = 34
144 = 44
145 = 34
146 = 65
147 = 103
148 = 105
149 = 110
150 = 103
151 = 34
152 = 44
153 = 34
154 = 65
155 = 100
156 = 118
157 = 101
158 = 114
159 = 116
160 = 105
161 = 115
162 = 105
163 = 110
164 = 103
165 = 34
166 = 44
167 = 34
168 = 65
169 = 108
170 = 99
171 = 111
172 = 104
173 = 111
174 = 108
175 = 34
176 = 44
177 = 34
178 = 65
179 = 115
180 = 105
181 = 97
182 = 34
183 = 93
184 = 125
185 = 0
186 = 0
187 = 0
188 = 0
189 = 0
190 = 0
191 = 0
192 = 0
193 = 0
194 = 0
195 = 0
196 = 0
197 = 0
198 = 0
199 = 0
----------------------- update ------------------------
I used the debugger to trace the problem and it seems like the gzipped response was decompressed twice. As shown in the pictures attached, read in InflaterSource.java is called twice. The exception is thrown at the second time it's being decompressed.
The first time read is called
The second time read is called, the exception is thrown
The server data is corrupt. It's supposed to contain a gzip trailer to indicate the end of the stream and that's missing.
I had this error on a retrofit GET request to a random site,I added
#Headers("Accept-Encoding: identity")
to fix it.
identity
Indicates the identity function (i.e. no compression, nor modification). This value is always considered as acceptable, even if not present.
you can use this code for getting inputstream. I hopeful it work for you.
private static String getResponseString(Response response) {
try {
InputStream inputStream;
String contentEncodingHeader = response.header("Content-Encoding");
if (contentEncodingHeader != null && contentEncodingHeader.equals("gzip")) {
// Read the zipped contents.
inputStream = new GZIPInputStream(response.body().byteStream());
} else {
// Read the normal contents.
inputStream = response.body().byteStream();
}
// Create and return buffered reader.
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
// Read stream.
StringBuilder sb = new StringBuilder("");
String line;
while ((line = br.readLine()) != null) {
sb.append(line.trim());
}
// Close everything.
response.body().close();
inputStream.close();
br.close();
return sb.toString();
} catch (IOException e) {
return "";
}
}
Description: I want to connect to server via POST request. My method, which posts the request:
function loginClick(e) {
var url = "http://...";
var xhr = Ti.Network.createHTTPClient({
onload: function (e) { // this function is called when data is returned from the server and available for use
// this.responseText holds the raw text return of the message (used for text/JSON)
// this.responseXML holds any returned XML (including SOAP)
// this.responseData holds any returned binary data
Ti.API.debug(this.responseText);
alert(xhr.responseText);
},
onerror: function (e) { // this function is called when an error occurs, including a timeout
Ti.API.debug(e.error);
alert(e.toString);
},
timeout: 5000 /* in milliseconds */
});
xhr.autoEncodeUrl = false;
var params = {
email: $.email.value,
password: $.password.value
};
xhr.open('POST', url);
xhr.send(params); // request is actually sent with this statement
Ti.API.info(xhr.responseText);
};
But I can't do it because receive strange message. I put it in the Logs. Besides, I did another requests and they worked successfully.
Logs:
[ERROR] : TiHttpClient: (TiHttpClient-1) [3529,3529] HTTP Error (org.apache.http.client.HttpResponseException): Not Found
[ERROR] : TiHttpClient: org.apache.http.client.HttpResponseException: Not Found
[ERROR] : TiHttpClient: at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:258)
[ERROR] : TiHttpClient: at ti.modules.titanium.network.TiHTTPClient$LocalResponseHandler.handleResponse(TiHTTPClient.java:217)
[ERROR] : TiHttpClient: at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)
[ERROR] : TiHttpClient: at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
[ERROR] : TiHttpClient: at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1287)
[ERROR] : TiHttpClient: at java.lang.Thread.run(Thread.java:841)
I solved it with JSON.stringify(params) with the sending the request :
function loginClick(e)
{
var url = 'http://...';
var xhr = Ti.Network.createHTTPClient({
onload: function(e) {
// this function is called when data is returned from the server and available for use
// this.responseText holds the raw text return of the message (used for text/JSON)
// this.responseXML holds any returned XML (including SOAP)
// this.responseData holds any returned binary data
Ti.API.debug(this.responseText);
alert(xhr.responseText);
},
onerror: function(e) {
// this function is called when an error occurs, including a timeout
Ti.API.debug(e.error);
alert(this.status);
alert("error" + e.toString);
},
timeout:5000 /* in milliseconds */
});
xhr.autoEncodeUrl = false;
var params = {
'email': $.email.value,
'password' :$.password.value
};
xhr.open('POST', url);
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.send(JSON.stringify(params)); // request is actually sent with this statement
};
The "Not Found" exception makes sense. I tried doing a POST with CURL to demonstrate that this isn't caused by Titanium. Your URL is wrong.
> curl --verbose --data "email=test#mail.com&password=dnipro" http://www.assignmentexpert.com/api/v1
* Adding handle: conn: 0x7ffdc4004400
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ffdc4004400) send_pipe: 1, recv_pipe: 0
* About to connect() to www.assignmentexpert.com port 80 (#0)
* Trying 198.72.112.182...
* Connected to www.assignmentexpert.com (198.72.112.182) port 80 (#0)
> POST /api/v1 HTTP/1.1
> User-Agent: curl/7.30.0
> Host: www.assignmentexpert.com
> Accept: */*
> Content-Length: 35
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 35 out of 35 bytes
< HTTP/1.1 404 Not Found
* Server nginx/1.4.7 is not blacklisted
< Server: nginx/1.4.7
< Date: Fri, 25 Apr 2014 16:45:58 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/5.4.26
< Set-Cookie: updater=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22d0a5527549f76365252a61361cd78e59%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A12%3A%2298.218.93.45%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A11%3A%22curl%2F7.30.0%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1398444358%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D7b00051302d9b00cd28b355be89a1e98; expires=Sun, 24-Apr-2016 16:45:58 GMT; path=/
< Set-Cookie: logged=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT
< Location: /api/v1/
<
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
(truncated -- HTML returned is identical to www.assignmentexpert.com)