2

I'm trying to create an Android app that connects to the Doorbird device, I know the company's official app, but, I need more features that are tailored to my needs.

For someone that doesn't know what is Doorbird device, Doorbird is a smart intercom, a product of Doorbird company, the device can transmit audio and video from him to any consumer, like Android system, over HTTP and RTSP and he can get Audio stream and play it, for example, to record audio from Android device and transmit it to Doorbird. The audio is in format G711 u-law.

I was able to get the video and audio stream received from Doorbird and it works perfectly but I don't succeed to transmit the audio, in the u-law format of course, to Doorbird. The error I get is HTTP FAILED: java.net.ProtocolException: Unexpected status line:

I tried to transmit the same bytes I get from Doorbird back to Doorbird but still the same error.

Of course, I work according to the API that they published but there is not much information about an agreed protocol to transmit audio. Offical Doorbird API

Is there an example of an Android project that integrates with Doorbird?

Can anyone help in trying to broadcast audio to Doorbird?

Which protocol should be?

Even someone who knows to transmit audio to Doorbird with any other tools and any system and not just Android OS, I'd appreciate it.

This is what I tried, I received the data from Doorbird (and as I said its works) and waiting 3 seconds, and transmit it with Retrofit Libray back to Doorbird.

    const val AUDIO_PATH =
"http://192.168.1.187/bha-api/audio-receive.cgi?http-user=XXXXXX0001&http-password=XXXXXXXXXX"
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)


    //InputStream inputStream = getResources().openRawResource(R.raw.piano12);
    val thread = Thread { this.playUrl() }
    thread.start()
    //val inStr = assets.open("doorbird_record")

}

private fun playUrl() {
    val inStr = URL(AUDIO_PATH).openStream()
    val buffer = ByteArray(1000)
    var i = 0

    //while (inStr.read(buffer).also { i = it } != -1) {


    Handler(Looper.getMainLooper()).postDelayed({
        //inStr.close()
        inStr.read(buffer)
        Log.d("DoorbirdLog", inStr.toString())
        val part = MultipartBody.Part.createFormData(
            "doorbirdStream", "doorbird", buffer.toRequestBody(
                ("audio/basic").toMediaType()
            )
        )
        //val rb = file.asRequestBody(("audio/*").toMediaType())
        val call = NetworkManager.instanceServiceApi.upload(part)
        call.enqueue(object : Callback<ResponseBody> {
            override fun onResponse(
                call: Call<ResponseBody>,
                response: Response<ResponseBody>
            ) {
                val i = response.body()
                Log.d("success", i.toString())
            }

            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                Log.d("failed", t.message.toString())
            }
        })

    }, 3000)

}

And the Retrofit instance:

@Multipart
@Headers( "Content-Type: audio/basic",
        "Content-Length: 9999999",
        "Connection: Keep-Alive",
        "Cache-Control: no-cache")
@POST("audio-transmit.cgi?http-user=XXXXXX0001&http-password=XXXXXXXXXX")
fun upload(@Part part: MultipartBody.Part): Call<ResponseBody>

I'd appreciate your assistance

Yonibagi
  • 147
  • 10

1 Answers1

3

Eventually, I was able to find a solution, I'll briefly present here the solution for those who will encounter an attempt to integrate with Doorbird.

private const val FREQUENCY_SAMPLE_RATE_TRANSMIT = 8000
private const val RECORD_STATE_STOPPED = 0

override suspend fun recordAndTransmitAudio(audioTransmitUrl: String) =
        withContext(Dispatchers.IO) {
            val minBufferSize = AudioRecord.getMinBufferSize(
                FREQUENCY_SAMPLE_RATE_TRANSMIT, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT
            )
            mRecorder = AudioRecord(
                MediaRecorder.AudioSource.VOICE_COMMUNICATION,
                FREQUENCY_SAMPLE_RATE_TRANSMIT, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, minBufferSize
            )
            mRecorder?.let { enableAcousticEchoCanceler(it.audioSessionId) }
            mRecorder?.startRecording()

            val bufferShort = ShortArray(minBufferSize)
            val buffer = ByteArray(minBufferSize)

            val urlConnection = URL(audioTransmitUrl).openConnection() as HttpURLConnection
            urlConnection.apply {
                doOutput = true
                setChunkedStreamingMode(minBufferSize)
            }

            val output = DataOutputStream(urlConnection.outputStream)
            output.flush()

            try {
                mRecorder?.let { recorder ->
                    while (recorder.read(bufferShort, 0, bufferShort.size) != RECORD_STATE_STOPPED) {
                        G711UCodecManager.encode(bufferShort, minBufferSize, buffer, 0)
                        output.write(buffer)
                    }
                }
            }catch (e: Exception){
                Log.d(TAG, e.message.toString())
            }
            output.close()
            urlConnection.disconnect()
        }
  1. First, we will prepare the necessary parameters for recording and transmission
  2. We get the minimum size of the buffer for recording
  3. Define the object with which we will record
  4. Activate the echo cancellation
  5. And start recording
  6. Open connection with the transmit URL
  7. While loop as long as the recording has not stopped
  8. Encode the data we recorded from PCM 16Bit format to G.711 μ-law format
  9. And of course, after we finished the recording we cleaned up resources.
Yonibagi
  • 147
  • 10