BASSenc_AAC (AAC encoding)

Started by Ian @ un4seen,

Ian @ un4seen

You can write an AAC file (see BASS_Encode_AAC_StartFile) but you can't currently set any tags while doing so. If tags are wanted, you could perhaps use an ID3 tagging library to add them to the written file afterwards.

orange

#22
I have tried all other formats, opus, ogg, and others, but the same result is compressing the audio, sending it, then receiving it and playing it. The problem is with playback with all libraries.

am use android java

                encodeHandle=     BASS_Encode_AAC_Start(recordChannel, "--object-type 2 --vbr 0 --bitrate 32000", 0,  encodeProcx,null);

 public static com.un4seen.bass.BASSenc.ENCODEPROCEX  encodeProcx = (int handle, int channel, ByteBuffer buffer, int length, long offset, Object user) -> {
        byte[] data = new byte[length];
      buffer.get(data);
     sendEncodedData(data);

    };

 ByteBuffer byteBuffer = ByteBuffer.wrap(encodedData);
        int channel = BASS_AAC_StreamCreateFile(byteBuffer, 0, encodedData.length, 0);

 BASS.BASS_ChannelPlay(channel, false);

I tried every method but the error appears every time I run it
error 41

Chris

Hi is that a Typo ?
You are encoding in AAC

and decoding in Opus?

orange

No, no, by mistake, I sent this code. I also use aac decompression

orange

I also used this method

Same problem, no sound ERROR 41

public void playReceivedData(byte[] data) {
        MyFileProcs procs = new MyFileProcs(data);

        int channel = com.un4seen.bass.BASS_AAC.BASS_AAC_StreamCreateFileUser( STREAMFILE_BUFFERPUSH, BASS_STREAM_DECODE, procs, null);

        if (channel == 0) {
            int error = BASS.BASS_ErrorGetCode();
            System.out.println("Error playing data: " + error);
        } else {
            BASS.BASS_ChannelPlay(channel, false);
        }
    }

    private class MyFileProcs implements BASS.BASS_FILEPROCS {
        private final byte[] data;
        private int position = 0;

        public MyFileProcs(byte[] data) {
            this.data = data;
        }

        @Override
        public int FILEREADPROC(ByteBuffer buffer, int length, Object user) {
            int bytesToCopy = Math.min(length, data.length - position);
            if (bytesToCopy <= 0) {
                return -1; // EOF
            }
            buffer.put(data, position, bytesToCopy);
            position += bytesToCopy;
            return bytesToCopy;
        }

        @Override
        public long FILELENPROC(Object user) {
            return data.length;
        }

        @Override
        public void FILECLOSEPROC(Object user) {}

        @Override
        public boolean FILESEEKPROC(long offset, Object user) {
            if (offset < 0 || offset > data.length) {
                return false;
            }
            position = (int) offset;
            return true;
        }

    }

Ian @ un4seen

To narrow down what/where the problem is, if you just write the encoded data to a file (not network) and then try playing that file, does that work?

If you want to send the data over a network, you could try BASSenc's built-in server feature (see BASS_Encode_ServerInit) and then BASS_StreamCreateURL on the client side. That should make things much simpler for you, eg. no need for callback functions. You can check the SERVER.C example (and pre-compiled SERVER.EXE) included in the BASSenc package for a demonstration.

orange

Quote from: Ian @ un4seenTo narrow down what/where the problem is, if you just write the encoded data to a file (not network) and then try playing that file, does that work?

If you want to send the data over a network, you could try BASSenc's built-in server feature (see BASS_Encode_ServerInit) and then BASS_StreamCreateURL on the client side. That should make things much simpler for you, eg. no need for callback functions. You can check the SERVER.C example (and pre-compiled SERVER.EXE) included in the BASSenc package for a demonstration.

I tried it and the same problem. Changing using all types has the same problem 


As for BASS_Encode_ServerInit, I used it and it succeeded, but there is a delay and I want to transfer in real time, so I used this method


                encodeHandle=     BASS_Encode_AAC_Start(recordChannel, "--object-type 2 --vbr 0 --bitrate 32000", 0,  encodeProcx,null);

 public static com.un4seen.bass.BASSenc.ENCODEPROCEX  encodeProcx = (int handle, int channel, ByteBuffer buffer, int length, long offset, Object user) -> {
        byte[] data = new byte[length];
      buffer.get(data);
     sendEncodedData(data);

    };

 ByteBuffer byteBuffer = ByteBuffer.wrap(encodedData);
        int channel = BASS_AAC_StreamCreateFile(byteBuffer, 0, encodedData.length, 0);

 BASS.BASS_ChannelPlay(channel, false);

AAC, OGG , OPUS   All Type  same problem 

Ian @ un4seen

Quote from: orangeI tried it and the same problem. Changing using all types has the same problem 

Strange. Please show the code you used to write the file, and the code you used to try to play it afterwards. Also try BASS_Encode_AAC_StartFile instead of BASS_Encode_AAC_Start, to check if the issue is something in your callback function.

orange

#29
When I send the data to the server and save it in a file, I can read it using VLC
The problem is reading the data

 ByteBuffer byteBuffer = ByteBuffer.wrap(encodedData);
        int channel = BASS_AAC_StreamCreateFile(byteBuffer, 0, encodedData.length, 0);

 BASS.BASS_ChannelPlay(channel, false); 

error 41

Ian @ un4seen

Quote from: orangeWhen I send the data to the server and save it in a file, I can read it using VLC

If you try opening the same file (not a ByteBuffer) with BASS_StreamCreateFile, does that work? If not, please upload (or link) the file to have a look at here:

   ftp.un4seen.com/incoming/

orange

#31
I could not play the file

  audioFilePath := 'output.aac';

  stream := BASS_StreamCreateFile(False, PChar(audioFilePath), 0, 0, 0);

error  2

I sent you the file   ftp.un4seen.com/incoming/


===============

I tried writing codes in Java and Delphi, but the problem is the same. Recording and compression works, but playing the file does not work

Chris

#32
Hi looks like you have a newer Delphi Version so


var
  AAC_Plugin: HPlugin;
  Fstream:HStream;

AAC_Plugin := BASS_PluginLoad(PWideChar('bass_aac.dll'),BASS_UNICODE);
if AAC_Plugin = 0 then
 // Errorhandling eg Bass_ErrorGetCode
else
   Fstream := BASS_StreamCreateFile(False, PWideChar(audioFilePath), 0,0, BASS_UNICODE);
  if fStream = 0 then
   // Errorhandling eg Bass_ErrorGetCode



orange

Quote from: ChrisHi looks like you have a newer Delphi Version so


var
  AAC_Plugin: HPlugin;
  Fstream:HStream;

AAC_Plugin := BASS_PluginLoad(PWideChar('bass_aac.dll'),BASS_UNICODE);
if AAC_Plugin = 0 then
 // Errorhandling eg Bass_ErrorGetCode
else
   Fstream := BASS_StreamCreateFile(False, PWideChar(audioFilePath), 0,0, BASS_UNICODE);
  if fStream = 0 then
   // Errorhandling eg Bass_ErrorGetCode


Thanks Chris

I noticed that when the samples are saved in memory and then played, they work well, but the sound playback time is delayed by a second or more. The question here is: Is the Bass library unable to play samples in real time??

Ian @ un4seen

The uploaded AAC file is playable with BASS_StreamCreateFile, so it seems like the issue may be something in your callback functions when using BASS_StreamCreateFileUser. Is your "playReceivedData" function called for each packet of data? If so, you shouldn't create a new stream for each packet, but rather create a single stream from the first packet and then feed the other packets to that too via BASS_StreamPutFileData. Your FILELENPROC should return 0 so that the stream doesn't end after the first packet. Note you should also pass any remaining data (not used by BASS_StreamCreateFileUser) from the first packet to BASS_StreamPutFileData after BASS_StreamCreateFileUser returns.

If you're still getting a BASS_ERROR_FILEFORM error from BASS_StreamCreateFileUser then it may be that your first packet doesn't contain enough data, in which case you can buffer the data and call BASS_StreamCreateFileUser when you have more.

orange

Quote from: Ian @ un4seenThe uploaded AAC file is playable with BASS_StreamCreateFile, so it seems like the issue may be something in your callback functions when using BASS_StreamCreateFileUser. Is your "playReceivedData" function called for each packet of data? If so, you shouldn't create a new stream for each packet, but rather create a single stream from the first packet and then feed the other packets to that too via BASS_StreamPutFileData. Your FILELENPROC should return 0 so that the stream doesn't end after the first packet. Note you should also pass any remaining data (not used by BASS_StreamCreateFileUser) from the first packet to BASS_StreamPutFileData after BASS_StreamCreateFileUser returns.

If you're still getting a BASS_ERROR_FILEFORM error from BASS_StreamCreateFileUser then it may be that your first packet doesn't contain enough data, in which case you can buffer the data and call BASS_StreamCreateFileUser when you have more.


Good, I understand. I will try it and I will let you know the results. Thank you very much

orange

Is it possible for a simple example of how to read the data? It did not work for me. I do not know where the problem is  ??? ???

Ian @ un4seen

Is your BASS_StreamCreateFileUser call still failing with BASS_ERROR_FILEFORM? If so, how much data are you providing it via your FILEREADPROC? The ADTS parser currently expects to see at least 3 ADTS frames to confirm that it is actually ADTS data. If you have less than that, try downloading more before calling BASS_StreamCreateFileUser and see if you still have the problem then.

orange

#38
Quote from: Ian @ un4seenIs your BASS_StreamCreateFileUser call still failing with BASS_ERROR_FILEFORM? If so, how much data are you providing it via your FILEREADPROC? The ADTS parser currently expects to see at least 3 ADTS frames to confirm that it is actually ADTS data. If you have less than that, try downloading more before calling BASS_StreamCreateFileUser and see if you still have the problem then.

wrote the code in Delphi to verify the problem, but it is the same  StreamHandle = 0


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase, IdUDPServer, Bass;

type
  TForm1 = class(TForm)
    IdUDPServer1: TIdUDPServer;
    procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
      const AData: TIdBytes; ABinding: TIdSocketHandle);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    StreamHandle: HSTREAM;
    AudioData: TBytes;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function FileReadProc(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
  if Assigned(user) then
  begin
    Move(PByteArray(user)^, buffer^, length);
    Result := length;
  end
  else
  begin
    Result := 0;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileProcs: BASS_FILEPROCS;
begin
  if BASS_Init(-1, 44100, 0, 0, nil) then
  begin
    FileProcs.READ := @FileReadProc;
 
    FileProcs.CLOSE := nil;
    FileProcs.LENGTH := nil;
    FileProcs.READ := nil;
    FileProcs.SEEK := nil;
   
    StreamHandle := BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER or BASS_STREAM_DECODE, BASS_STREAMFILE_BUFFER, @FileProcs, AudioData);

    if StreamHandle <> 0 then
    begin
      BASS_ChannelPlay(StreamHandle, False);
    end
    else
    begin
      ShowMessage('Error playing audio');
    end;
  end
  else
  begin
    ShowMessage('BASS initialization error');
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if StreamHandle <> 0 then
    BASS_StreamFree(StreamHandle);

  BASS_Free;
end;

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
  SetLength(AudioData, Length(AData));
  Move(AData[0], AudioData[0], Length(AData));
 // BASS_StreamPutFileData(StreamHandle, @AData[0], Length(AData));
end;

end.





 

Ian @ un4seen

Quote from: orangefunction FileReadProc(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
  if Assigned(user) then
  begin
    Move(PByteArray(user)^, buffer^, length);
    Result := length;
  end
  else
  begin
    Result := 0;
  end;
end;

This function should advance the read position by the amount that it returned, so that the next call doesn't return the same data. It also needs to check that the "length" parameter doesn't exceed the amount of data available. I'm not a Delphi user myself, but in C/C++ it could look something like this:

DWORD CALLBACK FileReadProc(void *buffer, DWORD length, void *user)
{
if (length > datalen - datapos) length = datalen - datapos; // limit it to available amount
memcpy(buffer, data + datapos, length); // read data
datapos += length; // advance read position
return length; // return read amount
}

Quote from: orange    FileProcs.READ := @FileReadProc;
 
    FileProcs.CLOSE := nil;
    FileProcs.LENGTH := nil;
    FileProcs.READ := nil;
    FileProcs.SEEK := nil;
   
    StreamHandle := BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER or BASS_STREAM_DECODE, BASS_STREAMFILE_BUFFER, @FileProcs, AudioData);

FileProcs.READ is nil?

For a file from the internet, you should usually use either the STREAMFILE_BUFFER or STREAMFILE_BUFFERPUSH systems (not STREAMFILE_NOBUFFER), depending on whether you want to use BASS_StreamPutFileData. Also, BASS_STREAM_DECODE should be in the "flags" parameter rather than the "system" parameter. For example:

    StreamHandle := BASS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_DECODE, @FileProcs, AudioData);

But it looks like you're currently calling BASS_StreamCreateFileUser without any data available? It needs to see some data (from the FILEREADPROC) to detect the format and initialize a decoder, so you should download some data before that.