Author Topic: Seek with StreamCreateFileUser  (Read 458 times)

dieppa

  • Posts: 33
Seek with StreamCreateFileUser
« on: 5 Apr '18 - 12:43 »
Hola,

I am implementing streaming from third party API such as Google Drive, Dropbox, etc, which returns me an InputStream rather than an URL. I am using BASS_StreamCreateFileUser to load the stream but I can't do seek when streaming from the Internet, I get error code 37. (Seeking from a FileInputStream just work fine). Curiously, when I use BASS.BASS_POS_DECODETO (instead of POS_BYTE) in BASS.BASS_ChannelSetPosition it seeks while streaming from the Internet but only forward, backwards returns error 7.

It is worth to mention that callback method FILESEEKPROC is never called.

Thanks.

Ian @ un4seen

  • Administrator
  • Posts: 21130
Re: Seek with StreamCreateFileUser
« Reply #1 on: 5 Apr '18 - 17:38 »
When using StreamCreateFileUser, seeking backwards will only be possible on the stream if the STREAMFILE_NOBUFFER system is used, or the STREAMFILE_BUFFER/PUSH system without the BASS_STREAM_BLOCK flag (and your FILELENPROC provides the file length). In the STREAMFILE_BUFFER/PUSH case, seeking forwards is only possible within the part that has been downloaded so far.

If you're getting a BASS_ERROR_NOTAVAIL error from BASS_ChannelSetPosition then that sounds like you're currently using the STREAMFILE_BUFFER/PUSH system with the BASS_STREAM_BLOCK flag or your FILELENPROC isn't providing the file length? In that case, seeking forwards is still possible via the BASS_POS_DECODETO option because that decodes up to the requested position (or as close as is currently available) rather than seeking in the file.

dieppa

  • Posts: 33
Re: Seek with StreamCreateFileUser
« Reply #2 on: 6 Apr '18 - 08:50 »
Hi Ian,

I load the song with STREAMFILE_NOBUFFER and still can't seek and FILE sourced songs won't be played.

Here below the song loading code:
Code: [Select]
StreamAdapter streamAdapter = this.streamAdapterBuilder.build(songPlayerModel.getSource());

        if (streamAdapter == null) {
            Log.e(TAG, "Invalid source");
            return OPERATION_ERROR;
        }

        InputStream inputStream;

        try {
            inputStream = streamAdapter.getStream(songPlayerModel.getPath());
        } catch (IOException e) {
            Log.e(TAG, "Couldn't retrieve stream from adapter: " + e.getLocalizedMessage());
            return OPERATION_ERROR;
        }

        if ((this.playerChannel = BASS.BASS_StreamCreateFileUser(BASS.STREAMFILE_BUFFER, 0, new BufferHandler(inputStream), 0)) == 0
                && (this.playerChannel = BASS.BASS_MusicLoad(songPlayerModel.getPath(), 0, 0, BASS.BASS_MUSIC_RAMP, 1)) == 0) {
            return LOAD_RESOURCE_ERROR;
        }

Seek method:
Code: [Select]
@Override
    public int seekTo(double time) {
        long amountOfBytes = BASS.BASS_ChannelSeconds2Bytes(this.playerChannel, time / 1000);
        if (BASS.BASS_ChannelSetPosition(this.playerChannel, amountOfBytes, BASS.BASS_POS_BYTE))
            return SUCCESS;
        else {
            return OPERATION_ERROR;
        }
    }

Using BASS_POS_DECODETO it seeks forward. Using BASS_POS_BYTE it won't seek in any direction.

Here is the the FILEPROCS class:
Code: [Select]
private class BufferHandler implements BASS.BASS_FILEPROCS {

        private InputStream inputStream;

        BufferHandler(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public void FILECLOSEPROC(Object o) {
            try {
                inputStream.close();
            } catch (IOException e) {
                Log.e(TAG, "Error when closing stream: " + e.getLocalizedMessage());
            }
            this.inputStream = null;
        }

        @Override
        public long FILELENPROC(Object o) {
            try {
                return this.inputStream.available();
            } catch (IOException e) {
                Log.e(TAG, "Error when getting available data in stream: " + e.getLocalizedMessage());
            }
            return 0;
        }

        @Override
        public int FILEREADPROC(ByteBuffer byteBuffer, int length, Object o) {
            byte[] buffer = new byte[length];
            byteBuffer.clear();
            int readByte = 0;
            try {
                readByte = this.inputStream.read(buffer);
                byteBuffer.put(buffer);
            } catch (IOException e) {
                Log.e(TAG, "Error when reading the stream: " + e.getLocalizedMessage());
            }
            return readByte;
        }

        @Override
        public boolean FILESEEKPROC(long offset, Object channel) {
            try {
                this.inputStream.skip(offset); //Don't know actually if it works, it never comes in
                return true;
            } catch (IOException e) {
                Log.e(TAG, "Error when trying to seek: " + e.getLocalizedMessage());
            }
            return false;
        }
    }

When the songPlayerModel.getSource() is FILE then it can be seeked.








« Last Edit: 6 Apr '18 - 09:11 by dieppa »

Ian @ un4seen

  • Administrator
  • Posts: 21130
Re: Seek with StreamCreateFileUser
« Reply #3 on: 6 Apr '18 - 14:26 »
The BASS_StreamCreateFileUser call in that code is using STREAMFILE_BUFFER rather than STREAMFILE_NOBUFFER. If you switch to STREAMFILE_NOBUFFER then your FILESEEKPROC function will get called, but note the "offset" parameter is an absolute value, which may be behind the file's current position (ie. to seek backwards), so I don't think "inputStream.skip" is appropriate there. You would need to use something like the RandomAccessFile class (which has a "seek" method) instead to support seeking.

dieppa

  • Posts: 33
Re: Seek with StreamCreateFileUser
« Reply #4 on: 16 Apr '18 - 12:30 »
Hi Ian,

When using RandomAccessFile I get error 41.

I am writing 500kb to the file before playing it. After that, playing and writing occur at the same time.
« Last Edit: 16 Apr '18 - 12:54 by dieppa »

Ian @ un4seen

  • Administrator
  • Posts: 21130
Re: Seek with StreamCreateFileUser
« Reply #5 on: 16 Apr '18 - 17:09 »
Error code 41 is BASS_ERROR_FILEFORM, which means the file's format wasn't recognised/supported. Is the same data accepted if you pass it to BASS_StreamCreateFile instead, eg. in a ByteBuffer? If so, perhaps there is a problem somewhere in your BASS_FILEPROCS callback functions. What does your logging in them show?

dieppa

  • Posts: 33
Re: Seek with StreamCreateFileUser
« Reply #6 on: 17 Apr '18 - 12:18 »
Ok, somehow, the way I am downloading the file it's corrupting it.
« Last Edit: 17 Apr '18 - 12:48 by dieppa »

dieppa

  • Posts: 33
Re: Seek with StreamCreateFileUser
« Reply #7 on: 17 Apr '18 - 15:41 »
Solved. Thanks Ian.