Hello again the AddFromURL seems to not work with ogg streams . I have tried setting AudioFormat = 1
but this does not work either. Is it possible to be implemented ? Thanks |
Administrator
|
This post was updated on .
Hello.
At the moment uos can stream mp3, aac and opus https://en.wikipedia.org/wiki/Opus_(audio_format) format. Opus uses ogg stream so "pure" ogg could be added. Do you know some web-radio that uses it so I can test it? Note that I would not be ale to do it before this summer (but you are welcome to do it ![]() |
Thank you . You can find OGG radios here
http://dir.xiph.org/codecs/Vorbis How about temp downloading and reading (so we can use the libsndfile lib) ? |
Administrator
|
OK, I will try the web ogg radio (asap).
> How about temp downloading and reading (so we can use the libsndfile lib) ? If there are "static" files it could be done but this is not how to do with live-radio stream. |
Administrator
|
This post was updated on .
CONTENTS DELETED
The author has deleted this message.
|
Administrator
|
This post was updated on .
CONTENTS DELETED
The author has deleted this message.
|
Hello thanks !
The decoding part of ogg is a mess . https://xiph.org/vorbis/doc/libvorbis/overview.html Here is the official decoding example /******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * * by the Xiph.Org Foundation https://xiph.org/ * * * ******************************************************************** function: simple example decoder ********************************************************************/ /* Takes a vorbis bitstream from stdin and writes raw stereo PCM to stdout. Decodes simple and chained OggVorbis files from beginning to end. Vorbisfile.a is somewhat more complex than the code below. */ /* Note that this is POSIX, not ANSI code */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <vorbis/codec.h> #ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */ #include <io.h> #include <fcntl.h> #endif #if defined(__MACOS__) && defined(__MWERKS__) #include <console.h> /* CodeWarrior's Mac "command-line" support */ #endif ogg_int16_t convbuffer[4096]; /* take 8k out of the data segment, not the stack */ int convsize=4096; extern void _VDBG_dump(void); int main(){ ogg_sync_state oy; /* sync and verify incoming physical bitstream */ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the bitstream user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ char *buffer; int bytes; #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ /* Beware the evil ifdef. We avoid these where we can, but this one we cannot. Don't add any more, you'll probably go to hell if you do. */ _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); #endif #if defined(macintosh) && defined(__MWERKS__) { int argc; char **argv; argc=ccommand(&argv); /* get a "command line" from the Mac user */ /* this also lets the user set stdin and stdout */ } #endif /********** Decode setup ************/ ogg_sync_init(&oy); /* Now we can read pages */ while(1){ /* we repeat if the bitstream is chained */ int eos=0; int i; /* grab some data at the head of the stream. We want the first page (which is guaranteed to be small and only contain the Vorbis stream initial header) We need the first page to get the stream serialno. */ /* submit a 4k block to libvorbis' Ogg layer */ buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,stdin); ogg_sync_wrote(&oy,bytes); /* Get the first page. */ if(ogg_sync_pageout(&oy,&og)!=1){ /* have we simply run out of data? If so, we're done. */ if(bytes<4096)break; /* error case. Must not be Vorbis data */ fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); exit(1); } /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ ogg_stream_init(&os,ogg_page_serialno(&og)); /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ /* I handle the initial header first instead of just having the code read all three Vorbis headers at once because reading the initial header is an easy way to identify a Vorbis bitstream and it's useful to see that functionality seperated out. */ vorbis_info_init(&vi); vorbis_comment_init(&vc); if(ogg_stream_pagein(&os,&og)<0){ /* error; stream version mismatch perhaps */ fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); exit(1); } if(ogg_stream_packetout(&os,&op)!=1){ /* no page? must not be vorbis */ fprintf(stderr,"Error reading initial header packet.\n"); exit(1); } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ /* error case; not a vorbis header */ fprintf(stderr,"This Ogg bitstream does not contain Vorbis " "audio data.\n"); exit(1); } /* At this point, we're sure we're Vorbis. We've set up the logical (Ogg) bitstream decoder. Get the comment and codebook headers and set up the Vorbis decoder */ /* The next two packets in order are the comment and codebook headers. They're likely large and may span multiple pages. Thus we read and submit data until we get our two packets, watching that no pages are missing. If a page is missing, error out; losing a header page is the only place where missing data is fatal. */ i=0; while(i<2){ while(i<2){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; /* Need more data */ /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1){ ogg_stream_pagein(&os,&og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(i<2){ result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0){ /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ fprintf(stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } result=vorbis_synthesis_headerin(&vi,&vc,&op); if(result<0){ fprintf(stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } i++; } } } /* no harm in not checking before adding more */ buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,stdin); if(bytes==0 && i<2){ fprintf(stderr,"End of file before finding all Vorbis headers!\n"); exit(1); } ogg_sync_wrote(&oy,bytes); } /* Throw the comments plus a few lines about the bitstream we're decoding */ { char **ptr=vc.user_comments; while(*ptr){ fprintf(stderr,"%s\n",*ptr); ++ptr; } fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate); fprintf(stderr,"Encoded by: %s\n\n",vc.vendor); } convsize=4096/vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ if(vorbis_synthesis_init(&vd,&vi)==0){ /* central decode state */ vorbis_block_init(&vd,&vb); /* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ /* The rest is just a straight decode loop until end of stream */ while(!eos){ while(!eos){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; /* need more data */ if(result<0){ /* missing or corrupt data at this page position */ fprintf(stderr,"Corrupt or missing data in bitstream; " "continuing...\n"); }else{ ogg_stream_pagein(&os,&og); /* can safely ignore errors at this point */ while(1){ result=ogg_stream_packetout(&os,&op); if(result==0)break; /* need more data */ if(result<0){ /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ }else{ /* we have a packet. Decode it */ float **pcm; int samples; if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ vorbis_synthesis_blockin(&vd,&vb); /* **pcm is a multichannel float vector. In stereo, for example, pcm[0] is left, and pcm[1] is right. samples is the size of each channel. Convert the float values (-1.<=range<=1.) to whatever PCM format and write it out */ while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){ int j; int clipflag=0; int bout=(samples<convsize?samples:convsize); /* convert floats to 16 bit signed ints (host order) and interleave */ for(i=0;i<vi.channels;i++){ ogg_int16_t *ptr=convbuffer+i; float *mono=pcm[i]; for(j=0;j<bout;j++){ #if 1 int val=floor(mono[j]*32767.f+.5f); #else /* optional dither */ int val=mono[j]*32767.f+drand48()-0.5f; #endif /* might as well guard against clipping */ if(val>32767){ val=32767; clipflag=1; } if(val<-32768){ val=-32768; clipflag=1; } *ptr=val; ptr+=vi.channels; } } if(clipflag) fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence)); fwrite(convbuffer,2*vi.channels,bout,stdout); vorbis_synthesis_read(&vd,bout); /* tell libvorbis how many samples we actually consumed */ } } } if(ogg_page_eos(&og))eos=1; } } if(!eos){ buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,stdin); ogg_sync_wrote(&oy,bytes); if(bytes==0)eos=1; } } /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); }else{ fprintf(stderr,"Error: Corrupt header during playback initialization.\n"); } /* clean up this logical bitstream; before exit we see if we're followed by another [chained] */ ogg_stream_clear(&os); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* must be called last */ } /* OK, clean up the framer */ ogg_sync_clear(&oy); fprintf(stderr,"Done.\n"); return(0); } |
Administrator
|
This post was updated on .
Hello.
Indeed, it does not seem to be "out-of-the-box" and will need some white nights + cups of coffee (that sadly I could not find now). |
I understand ... to me my reach is to do a controlled? FPHTTPClient to save as file and load it at your uos- libsndfile lib.
If i have success i will let you know |
Administrator
|
OK, good luck!
|
Administrator
|
This post was updated on .
Here a C example using libvorbisfile, it is much more easy-doable:
https://xiph.org/vorbis/doc/vorbisfile/vorbisfile_example_c.html #include <stdio.h> #include <stdlib.h> #include <math.h> #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" #ifdef _WIN32 #include <io.h> #include <fcntl.h> #endif char pcmout[4096]; int main(int argc, char **argv){ OggVorbis_File vf; int eof=0; int current_section; #ifdef _WIN32 _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); #endif if(ov_open_callbacks(stdin, &vf, NULL, 0, OV_CALLBACKS_NOCLOSE) < 0) { fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); exit(1); } { char **ptr=ov_comment(&vf,-1)->user_comments; vorbis_info *vi=ov_info(&vf,-1); while(*ptr){ fprintf(stderr,"%s\n",*ptr); ++ptr; } fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate); fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor); } while(!eof){ long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,¤t_section); if (ret == 0) { /* EOF */ eof=1; } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ } else { /* we don't bother dealing with sample rate changes, etc, but you'll have to */ fwrite(pcmout,1,ret,stdout); } } ov_clear(&vf); fprintf(stderr,"Done.\n"); return(0); } |
Hello ! I am back
I currently made this Thread that downloads the stream {This unit is part of United Openlibraries of Sound (uos)} { This is HTTP Thread Getter created by Andrew Haines -> andrewd207@aol.com License : modified LGPL. Fred van Stappen / fiens@hotmail.com Modded By TrustFm } unit uos_httpgetthreadfile; {$mode objfpc}{$H+} interface uses Classes, Dialogs, SysUtils, fphttpclient, openssl, { This implements the procedure InitSSLInterface } opensslsockets; type { TThreadHttpGetterFile } TThreadHttpGetterFile = class(TThread) private FileStream: TFileStream; FFPHTTPClient: TFPHTTPClient; FWantedURL: string; FIcyMetaInt: int64; FOnIcyMetaInt: TNotifyEvent; property OnIcyMetaInt: TNotifyEvent read FOnIcyMetaInt write FOnIcyMetaInt; procedure DoIcyMetaInt; function GetRedirectURL(AResponseStrings: TStrings): string; procedure Headers(Sender: TObject); protected procedure Execute; override; public FIsRunning: Boolean; ICYenabled: Boolean; property IcyMetaInt: int64 read FIcyMetaInt; property IsRunning: Boolean read FIsRunning; constructor Create(AWantedURL,Filename: string); destructor Destroy; override; procedure CancelDownload; end; implementation { TThreadHttpGetterFile } constructor TThreadHttpGetterFile.Create(AWantedURL,Filename: string); begin FreeOnTerminate := True; inherited Create(True); //create suspended ICYenabled := False; FIsRunning := True; FWantedURL := AWantedURL; FileStream := TFileStream.Create(Filename, fmCreate or fmOpenWrite); // Start; end; destructor TThreadHttpGetterFile.Destroy; begin FFPHTTPClient.Free; FileStream.Free; FIsRunning := False; inherited Destroy; end; procedure TThreadHttpGetterFile.CancelDownload; begin if Assigned(FFPHTTPClient) then FFPHTTPClient.Terminate; end; function TThreadHttpGetterFile.GetRedirectURL(AResponseStrings: TStrings): string; var S: string; F: integer; Search: string = 'location:'; begin Result := ''; for S in AResponseStrings do begin // WriteLn(S); F := Pos(Search, Lowercase(s)); if F > 0 then begin Inc(F, Length(Search)); Exit(Trim(Copy(S, F, Length(S) - F + 1))); end; end; end; procedure TThreadHttpGetterFile.DoIcyMetaInt; begin if Assigned(FOnIcyMetaInt) then FOnIcyMetaInt(Self); end; procedure TThreadHttpGetterFile.Headers(Sender: TObject); begin FIcyMetaInt := StrToInt64Def(TFPHTTPClient(Sender).GetHeader(TFPHTTPClient(Sender).ResponseHeaders, 'icy-metaint'), 0); if (FIcyMetaInt > 0) and (FOnIcyMetaInt <> nil) then Synchronize(@DoIcyMetaInt); end; procedure TThreadHttpGetterFile.Execute; var URL: string; err: shortint = 0; begin URL := FWantedURL; if pos(' ', URL) > 0 then FIsRunning := False else begin InitSSLInterface; FFPHTTPClient := TFPHTTPClient.Create(nil); FFPHTTPClient.AllowRedirect := True; FFPHTTPClient.IOTimeout := 2000; //repeat try FFPHTTPClient.RequestHeaders.Clear; if ICYenabled = True then begin FFPHTTPClient.OnHeaders := @Headers; end; // writeln(' avant http.get'); FFPHTTPClient.HTTPMethod('GET',URL,FileStream,[200, 206]); //Http.Get (URL, FileStream); if not FFPHTTPClient.Terminated then begin //Synchronize... end; except on e: EHTTPClient do begin // writeln(' Http.ResponseStatusCode ' +inttostr(Http.ResponseStatusCode)); if (FFPHTTPClient.ResponseStatusCode > 399) or (FFPHTTPClient.ResponseStatusCode < 1) then // not accessible begin FIsRunning := False; //break; end; if FFPHTTPClient.ResponseStatusCode = 302 then begin URL := GetRedirectURL(FFPHTTPClient.ResponseHeaders); if URL <> '' then begin // writeln(' avant http.get'); FFPHTTPClient.HTTPMethod('GET',URL,FileStream,[200, 206]); //Http.Get (URL, FileStream); if not FFPHTTPClient.Terminated then begin //Synchronize... end; //Continue; end; end else begin //Break; // raise E; end; end; on e: Exception do begin //WriteLn(e.Message); end else begin //// Raise; //Break; end; end; //Break; //until (False); try //FileStream.Free; //Http.Free; finally // make sure this is set to false when done FIsRunning := False; end; end; end; end. ******************** the stream can be cancelled correctly using : procedure TForm1.Button5Click(Sender: TObject); var Filename : string; url: string; begin url := EditURL.text; Filename := 'dl.ogg'; HttpGetterFile := TThreadHttpGetterFile.Create(url,Filename); //create thread suspended HttpGetterFile.Start; end; procedure TForm1.Button6Click(Sender: TObject); begin HttpGetterFile.CancelDownload; end; ***************************************** The problem with the original streaming solution uos_httpgetthread is that the stream once started can not be stopped and i think that this has to do with the repeat loop inside the thread . The same issue happens on the streaming demo if you try on cascade mp3,opus,acc the uos_httpgetthread does not stop by calling the uos_stop |
Administrator
|
WoW!
Are you able to play radio-streams, like this: http://stream.dancewave.online:8080/dance.ogg ? I jumped too using libvorbisfile.so. I have some things working, like connect to the url, get the ogg-tags (titel, genre, ...) but it fails to read the pipe in the loop. In attachment zip of the units "work-on-progress", if you want to test it. uos_oggwebstreams.zip |
Administrator
|
Re-hello.
Note that uos_httpgetthread.pas has debug code, it is not yet fully working, it is to test where is the problem that will be removed when it works. But sure if you find something wrong, please fix it. |
Administrator
|
Re-hello.
I think that I will switch to curl library for UOS web-stream in uos_httpgetthread.pas. Sadly, fphttpclient.pas has too much problems to access web-steams, some protocol are not yet ready and only fpc 3.3.1 seems to resolve things. libcurl is present by default on many os and is cross-platform. What do you think? |
This post was updated on .
i think curl will be more powerful. i am not an expert . I am testing your code above .
My code above only downloads streams (in general) correctly (and can be stopped correctly) and are playable with uos_AddFromFile BUT work only for few seconds/minute since the downloaded file does not get "updated" once the user press uos_Play() so pretty useless ... The download part works 100% Give me some time now i am testing your code |
This post was updated on .
i have tested your code over the webstream demo crashes but the LOADLIBs functions works with vorbis added
this part works if uos_LoadLib(PChar(Editportaudio.Text), PChar(EditLinsbdfile.Text), PChar(Editmpg123.Text), nil, nil, PChar(Editopus.Text), nil, PChar(Editaac.Text), PChar(EditVorbis.Text)) = 0 then // I am using libvorbisfile.so.3.3.8 I only had to correct two ppchar to pchar in order to compile ... |
Administrator
|
This post was updated on .
In reply to this post by trustfm
I have just finish uos_httpgetthread_curl.pas who is the the same as uos_httpgetthread.pas but using curl lib vs fphttpserver.
So you have now the choice, or use uos_httpgetthread_curl.pas or uos_httpgetthread.pas for web-streaming. You may set it in uos_define.inc before to compile. Of course choose one of both, not both. Also always use the -B (build all) fpc parameter if you change something in uos_define.inc. {.$DEFINE webstream} // uncomment to enable Internet Audio Streaming using fpc fphttpclient. {$DEFINE webstream_curl} // uncomment to enable Internet Audio Streaming using curl lib. Tested in Linux 64 bit and webstream_curl works great for MP3, Opus and AAC. But sadly, I am still blocked at the same point for reading/playing the buffer of OGG, this method resists: ov_read(). I will need more withe nights... Here the new uos files in attachment: uos_curl.zip |
Administrator
|
This post was updated on .
In reply to this post by trustfm
Ho, the webstream demos are not updated yet, sorry, it is on my big todo list.
Here the libvorbisfile I use for Linux 64. libvorbisfile-64.zip The format of OGG in AddFromURL() is 3. I begin to suspect that maybe the libvorbisfile I use is not ok. |
Administrator
|
If you want to test webstream using uos_httpgetthread_curl.pas, at the moment the code search for libcurl.so.4 in your system.
If you system does not have it, you may change line 60 in uos_httpgetthread_curl.pas: CURL_LIB_NAME = 'libcurl.so.4'; // change with what you have, it will be tuned later in array of names. |
Free forum by Nabble | Edit this page |