0

I need to get data from native network call with CPP. from native i am getting chunks of data as i strat to receive the response in native functions and i am appending byte[] to ByteArrayOutputStream. i have created a custom datasource and in Read callback i am using ByteArrayOutputStream to read byte[] from based on offset. i am also using BlockingQueue to block the execution till we get enough byte[] to read.

The main issue i am having is in syncing the byte[] for exoplayer buffer. and when it works, it buffers a lot even with full byte[]. i am adding the code block for Open, Read and Close callbacks. Please let me know if i should try anything differently.

Open callback

@Override
    public long open(DataSpec dataSpec) {
        Log.e("data_source", "open : " + dataSpec.toString());
        transferInitializing(dataSpec);
        // initiate native call to get the data
        bytesAlreadyRead = 0;
        opened = true;
        transferStarted(dataSpec);
        // blocking execution to get content length
        return contentLength.take();
    }

Read callback

@Override
    public int read(byte[] buffer, int offset, int readLength) {
        // Get latest data from `ByteArrayOutputStream`
        byte[] data = getLatestData();
        if (data.length < contentLength && data.length < (readLength + bytesAlreadyRead)) {
            try {
                //Blocking the execution until we get enough bytes
                String response = responseQueue.take()
                data = getLatestData();
            } catch (Exception ex) {
                Log.e("data_source", ex.getMessage());
            }
        }

        int byteAvailableToRead = (int) (data.length - bytesAlreadyRead);
        int bytesReadThisTime = Math.min(byteAvailableToRead, readLength);
        System.arraycopy(data, bytesAlreadyRead, buffer, offset, bytesReadThisTime);
        bytesAlreadyRead += bytesReadThisTime;
        bytesTransferred(bytesReadThisTime);
        return bytesReadThisTime;
    }

Close callback

@Override
    public void close() {
        Log.e("data_source","close : ");
        if (opened) {
            opened = false;
            transferEnded();
        }
        uri = null;
    }
deeppandya
  • 43
  • 1
  • 8

1 Answers1

-1

#chatgpt-4enter code here Based on the provided code and the description of the problem, it looks like you're trying to integrate a native data source with ExoPlayer in Android. The use of a BlockingQueue to synchronize the reading of the byte data is a good approach to ensure that the reading doesn't happen until the required data is available.

However, there are a few considerations and possible improvements to make your data source work efficiently:

Avoid Unnecessary Copies: Each time you call getLatestData(), if it creates a new copy of the byte array from the ByteArrayOutputStream, this is an unnecessary overhead. Instead, consider reading the data directly from the ByteArrayOutputStream without converting it multiple times.

Content Length: It seems that you are waiting in the open method to get the content length. If the content length is not known ahead of time, you might consider returning C.LENGTH_UNSET which indicates an unknown length in ExoPlayer.

Partial Blocking: In the read method, you're using responseQueue.take(). If you block indefinitely, and there's no data coming, your player will hang. Consider using poll with a timeout instead. This will allow the function to return after waiting for a certain amount of time, so you can handle situations where the data source might not provide data for a while.

EOF Handling: If you've reached the end of your data source, the read method should return -1 to indicate that there's no more data to be read. Synchronization: If your native method and the ExoPlayer callbacks run on different threads, you might run into synchronization issues. Consider using synchronized blocks or other synchronization mechanisms to ensure thread-safety. A revised version of the read callback:

@Override
public int read(byte[] buffer, int offset, int readLength) {
    byte[] data = byteArrayOutputStream.toByteArray();

    // Check if we have reached the end
    if (bytesAlreadyRead == data.length) {
        return -1; // EOF
    }

    if (data.length - bytesAlreadyRead < readLength) {
        try {
            // Blocking for a limited time 
            responseQueue.poll(100, TimeUnit.MILLISECONDS); 
            data = byteArrayOutputStream.toByteArray();
        } catch (Exception ex) {
            Log.e("data_source", ex.getMessage());
        }
    }

    int byteAvailableToRead = (int) (data.length - bytesAlreadyRead);
    int bytesReadThisTime = Math.min(byteAvailableToRead, readLength);
    System.arraycopy(data, bytesAlreadyRead, buffer, offset, bytesReadThisTime);
    bytesAlreadyRead += bytesReadThisTime;
    bytesTransferred(bytesReadThisTime);
    return bytesReadThisTime;
}

Lastly, remember to handle errors gracefully. For example, if there's an error in your native layer and no data is ever produced, you'd want to handle this in your player to provide feedback to the user or to attempt a retry.

Villsty
  • 1
  • 1