Author Topic: OPUS Encode and Decode  (Read 614 times)

nikos

  • Posts: 63
OPUS Encode and Decode
« on: 5 Aug '19 - 19:06 »
How can i play a stream created with BASS_Encode_OPUS_Start.
I have do the follow.


Code: [Select]
function recordACM(channel: HENCODE; chan:DWORD;buffer: Pointer; len:DWORD; user: DWORD): Boolean; stdcall;
begin
form1.xudp.SendBuffer(rawtoBytes(buffer^,len));
result:=true;
end;



Code: [Select]
  rchan := BASS_RecordStart(44100, 2, BASS_RECORD_PAUSE, @RecordingCallback, 0);
  if rchan = 0 then  begin    Error('Couldn''t start recording 2');    Exit;  end;
  BASS_Encode_OPUS_Start(rchan, '-M 80 -m 80', BASS_ENCODE_AUTOFREE or BASS_UNICODE, @recordACM, nil);
  BASS_ChannelPlay(rchan, FALSE); // resume recoding

BASSProcs.close := Bass_Close;
BASSProcs.length := Bass_Length;
BASSProcs.read := Bass_Read;
BASSProcs.seek := Bass_Seek;
playchan :=   BASS_OPUS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_AUTOFREE, BASSProcs,nil);
BASS_ChannelPlay(playchan, false);

and on UDP recieve i DO

BASS_StreamPutData(playchan, AData, length(adata));

but i dont hear anything.
If i dont use Opus Everything is fine.

Any Help?



Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #1 on: 6 Aug '19 - 15:23 »
What does your FILEREADPROC callback function (Bass_Read) look like? Note that some file data will be needed by BASS_OPUS_StreamCreateFileUser to initialize the decoder, and the FILEREADPROC is where it gets that data from. You should check the BASS_OPUS_StreamCreateFileUser return value to see if it was successful (it will likely fail if the FILEREADPROC isn't working properly). After the stream has been created, you can then use BASS_StreamPutFileData (not BASS_StreamPutData) to provide more data.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #2 on: 6 Aug '19 - 17:53 »
here is The record chan

Code: [Select]
rchan := BASS_RecordStart(44100, 2, BASS_RECORD_PAUSE or BASS_UNICODE, nil, 0);
BASS_Encode_OPUS_Start(rchan, '-M 80 -m 80', BASS_ENCODE_AUTOFREE or BASS_UNICODE, nil, nil);
BASS_ChannelPlay(rchan, FALSE);


BASSProcs.close := Bass_Close;
BASSProcs.length := Bass_Length;
BASSProcs.read := Bass_Read;
BASSProcs.seek := Bass_Seek;
playchan:=BASS_OPUS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_AUTOFREE or BASS_UNICODE, BASSProcs,nil);
BASS_ChannelPlay(playchan, FALSE); // resume recoding


This is My bass_read


Code: [Select]
Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
UDPCL.SendBuffer(rawtoBytes(buffer^,length));
End;

And here is The recive Data
Code: [Select]
BASS_StreamPutFileData(playchan, AData, length(adata));


All i want to do is ENCODE with any format the Audio Signal before i send it to UDP server .
I try many things from your post

I want to do the follow.

Code: [Select]
RecordChannel := BASS_RecordStart(44100 or what ever, 1 or 2 , BASS_RECORD_PAUSE, @RecordingCallback, 0);
BASS_ChannelPlay(RecordChannel, FALSE);
then i want to Compress This RecodChannel in a format i try

Code: [Select]
  CompressedChannel:=BASS_Encode_Start(RecordChannel, 'oggenc -r -R 44100 -M 80 -m 80 -', BASS_ENCODE_NOHEAD or BASS_ENCODE_AUTOFREE , @recordACM, 0);
  BASS_ChannelPlay(CompressedChannel, FALSE); // resume recoding

And on @recordACM i want to send The data to the udp server which i successfully I am sending
with the line of code

Code: [Select]
UPDCLIENT.SendBuffer(rawtoBytes(buffer^,len));
And when i recive the data and do the

Code: [Select]
BASS_StreamPutData(CompressedChannel, Buffer, length(Buffer));

I hear Nothing Thats is my problem.

What is The best Compression ( i dont care about quality its for voip ) to do ?
So the Data Length will be as minimal it can?







And please Check your Emails i sent to support i want to Buy the licence .
« Last Edit: 6 Aug '19 - 19:02 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #3 on: 7 Aug '19 - 13:29 »
This is My bass_read


Code: [Select]
Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
UDPCL.SendBuffer(rawtoBytes(buffer^,length));
End;

A FILEREADPROC function provides file data to BASS, so it needs to receive data from the socket (not send it) and give the amount received in the return value. If there is no data immediately available then it should wait for some to arrive (if more is expected).

Note that a FILESEEKPROC is not required when using the buffered file system (eg. STREAMFILE_BUFFERPUSH), so you can set that to "nil" instead of "Bass_Seek".

What is The best Compression ( i dont care about quality its for voip ) to do ?
So the Data Length will be as minimal it can?

Opus will probably be best for low latency.

To minimize latency, you should also request a short period in your BASS_RecordStart call. For example:

Code: [Select]
rchan := BASS_RecordStart(44100, 2, MAKELONG(BASS_RECORD_PAUSE, 5), @MyRecordProc, 0); // record with 5ms period

Note that you should still provide a RECORDPROC even if it does nothing but return true:

Code: [Select]
function MyRecordProc(channel: HENCODE; chan:DWORD;buffer: Pointer; len:DWORD; user: DWORD): Boolean; stdcall;
begin
  result:=true;
end;

The alternative is to periodically call BASS_ChannelGetData to process the recording, but it is simpler to just provide a RECORDPROC. Please see the BASS_RecordStart documentation for details.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #4 on: 7 Aug '19 - 14:25 »
bUt In Function Bass_read I want to sent The data to A server side and there to create a bass Stream to Play them back.
I want to sent The encoded Buffer.
it works fine with the recordCallback when i am not using encoder

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #5 on: 7 Aug '19 - 15:48 »
You would do the sending in an ENCODEPROC callback function, set in a BASS_Encode_OPUS_Start call, like you wrote in the first post. The function's signature in that post is incorrect though. It should be this:

Code: [Select]
procedure recordACM(channel: HENCODE; chan:DWORD;buffer: Pointer; len:DWORD; user: Pointer); stdcall;
begin
form1.xudp.SendBuffer(rawtoBytes(buffer^,len));
end;

By the way, "-M 80 -m 80" are not valid Opus encoding options. You probably want "--bitrate 80 --cvbr". Please see the BASS_Encode_OPUS_Start documentation (and the OPUSENC documentation link there) for details.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #6 on: 7 Aug '19 - 16:09 »
Mr ian you are very kind i will give i try now.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #7 on: 7 Aug '19 - 16:32 »
I Did Exactly what you told me

On client side i am sending the buffer like this.

Code: [Select]
procedure recordACM(channel: HENCODE; chan:DWORD;buffer: Pointer; len:DWORD; user: Pointer); stdcall;
begin
form1.IdUDPClient1.SendBuffer(rawtoBytes(buffer^,len));
end;
here is The recodChannel and the encoder

Code: [Select]
rchan := BASS_RecordStart(22050, 2,  MAKELONG(BASS_RECORD_PAUSE, 5), @RecordingCallback, 0);
BASS_Encode_OPUS_Start(rchan, '--bitrate 80 --cvbr', BASS_ENCODE_AUTOFREE or BASS_UNICODE, @recordACM, nil);


And now on server side i created a Hstream

Code: [Select]

Procedure Bass_Close(user: Pointer); stdcall;
Begin
End;

Function Bass_Length(user: Pointer): QWORD; stdcall;
Begin
End;

Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
End;

Function Bass_Seek(offset: QWORD; user: Pointer): BOOL; stdcall;
Begin
End;


BASSProcs.close := Bass_Close;
BASSProcs.length := Bass_Length;
BASSProcs.read := Bass_Read;
BASSProcs.seek := Bass_Seek;

playchan :=   BASS_OPUS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_AUTOFREE OR BASS_UNICODE, BASSProcs,nil);
BASS_ChannelPlay(playchan, false);


and on Recieve Data I do a

Code: [Select]
BASS_StreamPutFileData(playchan, adata, length(adata));
also i try
Code: [Select]
BASS_StreamPutData(playchan, adata, length(adata));

no luck.

Data are coming but i Hear Nothing.
« Last Edit: 7 Aug '19 - 16:36 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #8 on: 7 Aug '19 - 17:26 »
With that code, the BASS_OPUS_StreamCreateFileUser call will be failing (playchan=0). As I wrote in my first reply, BASS_OPUS_StreamCreateFileUser needs your Bass_Read function to provide data to initialize the decoder with. Your Bass_Length function should also return something (you can use 0 there).

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #9 on: 7 Aug '19 - 17:50 »
How can i Do it?
Even if you give me an example in C++ i will appreciate.
The data Comes on my socket how to Call The bass_read to push them there?

I created a Memtory stream On start

and in read_bass I did 

Code: [Select]
buffer:=MyMemoryStream.Memory;
and when i recieve The data on UDP
I do a
Code: [Select]
MymemoryStream.write(DATA,Length(data))


But playchan still= 0

Error code= BASS_ERROR_FILEFORM

« Last Edit: 7 Aug '19 - 18:02 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #10 on: 7 Aug '19 - 18:00 »
In C/C++, you might call recv or recvfrom in the FILEREADPROC function.

If the data is being received asynchronously in a different function then you will need have that put the data in a FIFO buffer and have your Bass_Read function read from that buffer.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #11 on: 7 Aug '19 - 18:05 »
Okey i got it  ut when i try to create the playchan i get error bass fileform how can i fix this please
« Last Edit: 7 Aug '19 - 22:52 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #12 on: 8 Aug '19 - 13:13 »
A BASS_ERROR_FILEFORM error means that the format of the provided data was not recognised. That could be caused by a problem in your FILEREADPROC function (Bass_Read). What does that function look like now? You can confirm if the data is valid by having the FILEREADPROC function also write it to a file and then seeing if the written file is playable (in any player that supports Opus).

Note that the Opus decoder will need the data exactly as was produced by the Opus encoder, eg. you cannot skip the start/headers.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #13 on: 8 Aug '19 - 14:40 »
Thanks ian i stick with Uncompressed data because i dont have an example with a bass_read proc so i undestand what it expects.

What i try was.
Create a Tmemory Stream
Each Time DataArived on my socket i put memorystream.position:=0 Then i write the data to the stream
and the Bass_read fileproc I Did a
buffer:=mymemorystream.memory;
result:=mymemorystream.size;
but the problem is that i try to Create The opus_fileuser channel before i have recieve any  data.

Any way as i said i can stay with uncompressed data it works just great!

I sent you an email i bought the shareware licence for android and i tank you for all support.
thanks again.




Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #14 on: 8 Aug '19 - 16:08 »
What i try was.
Create a Tmemory Stream
Each Time DataArived on my socket i put memorystream.position:=0 Then i write the data to the stream
and the Bass_read fileproc I Did a
buffer:=mymemorystream.memory;
result:=mymemorystream.size;
but the problem is that i try to Create The opus_fileuser channel before i have recieve any  data.

When data is received from the socket, you should add it to (not replace) any already buffered data. And the FILEREADPROC function should read from the buffer, up to the amount requested in the "length" paramater. If no data is immediately available, it should wait for some to arrive (if more is expected).

Regarding examples, I don't use Delphi myself so I'm afraid I'm unable to advise on that, but here are a couple of C/C++ examples (TCP rather than UDP though):

   www.un4seen.com/forum/?topic=16871.msg118037#msg118037
   www.un4seen.com/forum/?topic=8319.msg57022#msg57022

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #15 on: 8 Aug '19 - 16:11 »
Thank You Thank You Thank You!

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #16 on: 11 Aug '19 - 16:17 »
Okey here is my simple try again.


My Initialize
Code: [Select]
if (not BASS_RecordInit(-1)) or (not BASS_Init(-1, 44100, 0, 0, nil)) then begin  Showmessage(BASS_ErrorToString(BASS_ErrorGetCode));  Halt;   end;
BASS_PluginLoad('bassenc.dll', BASS_UNICODE);
BASS_PluginLoad('bassopus.dll', BASS_UNICODE);
BASS_PluginLoad('bassenc_opus.dll', BASS_UNICODE);
r:=BASS_Encode_GetVersion();
r:=BASS_Encode_OPUS_GetVersion();


rchan is  HRECORD



Code: [Select]



function RecordingCallback(channel: HRECORD; buffer: Pointer; length, user: DWORD): Boolean; stdcall;
begin
result:=true;
end;

//my encodeCallback Function
procedure EncodeCallback(handle:HENCODE; channel:DWORD; buffer:Pointer; length:DWORD; user:Pointer) stdcall;
begin
myStream.write(buffer^,length); //save Buffer to Mystream for later use
if length>0 Then BASS_StreamPutFileData(playchan, buffer, length);// put data if length >0 to playchannel
end;




rchan := BASS_RecordStart(44100, 2, BASS_RECORD_PAUSE , @RecordingCallback, 0);
BASS_ChannelPlay(rchan, FALSE); //works OkeY


myStream:=TmemoryStream.create; //i create a buffer to save Encoded Data Buffer and feed the Playchan which is a BASS_StreamCreateFileUser

EncodeChan:=BASS_Encode_OPUS_Start(rchan, '-M 80 -m 80',0 , @EncodeCallback, nil);
if EncodeChan=0 then begin  Showmessage(BASS_ErrorToString(BASS_ErrorGetCode)); Exit; end;
BASS_ChannelPlay(EncodeChan, FALSE);











And now i am trying to listen the encoded data buffer with

Code: [Select]
BASSProcs.close := Bass_Close;
BASSProcs.length := Bass_Length;
BASSProcs.read := Bass_Read;
BASSProcs.seek := nil;
playChan:=BASS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, 0, BASSProcs, Nil);
if playChan=0 then begin  Showmessage(BASS_ErrorToString(BASS_ErrorGetCode));  Exit; end;
BASS_ChannelPlay(playChan, FALSE); // resume recoding

Code: [Select]
Function Bass_Length(user: Pointer): QWORD; stdcall;
Begin
Result := 0;
End;

Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
var i:Integer;
begin

while myStream.Size=0 do
begin
i:=i; //loop infinity until there is some data in mystream
end;

buffer:=myStream.Memory; //here i put in BUFFER what mystream has already
length:=myStream.Size;
result:=length; //return length of Mystream
End;


Procedure Bass_Close(user: Pointer); stdcall;
Begin
//myStream.Free;
End;





on playChan:=BASS_StreamCreateFileUser  i get ERROR BASS_ERROR_FILEFORM because Bass_Close is Triggered
this example has not UDP and Sockets How can i Listen on Playchannel the encoded DATA?this is all i want.














« Last Edit: 11 Aug '19 - 16:22 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #17 on: 12 Aug '19 - 13:48 »
Code: [Select]
Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
var i:Integer;
begin

while myStream.Size=0 do
begin
i:=i; //loop infinity until there is some data in mystream
end;

buffer:=myStream.Memory; //here i put in BUFFER what mystream has already
length:=myStream.Size;
result:=length; //return length of Mystream
End;

That doesn't look right. This function (FILEREADPROC) should put up to "length" bytes of data in the provided "buffer", and return the actual amount put there. Each call should continue from where the last one left off. For example, if the first call asks for 1000 bytes then second call would start from position 1000. I'm not a Delphi user myself, but perhaps something like this:

Code: [Select]
Function Bass_Read(buffer: Pointer; length: DWORD; user: Pointer): DWORD; stdcall;
begin
  result:=writestream.Read(buffer^, length);
End;

For the "loop infinity until there is some data in mystream" part, I would suggest using an event instead, ie. wait for an event to be set (when data is received) or timeout. It looks like Delphi has TEvent for that.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #18 on: 12 Aug '19 - 13:53 »
i create a new post without sockets maybe you can help me in there ian thanks.
yes i use Tvent like timer with timeout But all i want is a simple example like i posted in the new Thread to play back the recorded data maybe you can help me there i create a new one.
« Last Edit: 12 Aug '19 - 13:57 by nikos »

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #19 on: 12 Aug '19 - 14:00 »
The same thing applies to your other post as it is using basically the same FILEREADPROC function.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #20 on: 12 Aug '19 - 14:04 »
os let me see if i understand right.

I start an record ChanneL
Then i start an opus Encoder channel with call back function
In this callback function i store the ENcoded Data to a MemoryStream.

then i create a playchan.
is not any way to take the encoded DATA buffer an just Put it in The Playchan i created on my Encoded CallBack  Fucntion?
And if is not
the BAS_READ is waitting Data from my Memorystream ---> Buffer?  or The oposite way there i am lost.
and where i put The  BASS_StreamPutFileData(playchan, buffer, length); Inside my EncodeProc? Or inside The bass_read function?




Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #21 on: 12 Aug '19 - 15:31 »
You would call BASS_StreamPutFileData in the ENCODEPROC function ("EncodeCallback") after BASS_StreamCreateFileUser has returned, ie. when you have a handle ("playChan") to use in the call. The buffer ("myStream") is only needed while creating the stream. Note that you should also pass any data that's left in the buffer to BASS_StreamPutFileData.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #22 on: 12 Aug '19 - 15:44 »
Thank you again and sorry for keep asking You.
Forget about UPD servers and Networking if i see a full example in C++ about how to Play a OPUS stream with bass_opus_createfileuser i will manage to translate it to Delphi.
Anything i try anything i read in this forumgives me back always Playchan=0 BAD FILEFORM
I dont knwo what to do i am stack 6 days now on delphi and bass :)
I search all samples no luck.

Ian @ un4seen

  • Administrator
  • Posts: 21991
Re: OPUS Encode and Decode
« Reply #23 on: 12 Aug '19 - 17:14 »
Here are a couple of examples of using the STREAMFILE_BUFFERPUSH system:

   www.un4seen.com/forum/?topic=8319.msg57022#msg57022
   www.un4seen.com/forum/?topic=9412.msg65672#msg65672

That 2nd example is more similar to what you want to do, eg. the OnReceiveData code goes in your EncodeCallback function. The code will be the same regardless of the file format, ie. it doesn't matter if it's Opus or MP3 or whatever.

nikos

  • Posts: 63
Re: OPUS Encode and Decode
« Reply #24 on: 12 Aug '19 - 17:58 »
yes i was just reading This Example http://www.bass.radio42.com/help/html/24e879fc-fc1f-c217-746e-e22a9e4f9d12.htm

Thank you again Ian