📄 shoutcaststream.pas
字号:
begin
if not GetICYSuccessfullyConnected(FICYHeader, ErrMsg) then
begin
GFFilterCallBack.AsyncExICYNotice(ICYError, PChar(ErrMsg));
end;
// try to get icy informations
GFFilterCallBack.AsyncExICYNotice(PChar(ICYName),
PChar(GetServerICYName(FICYHeader)));
GFFilterCallBack.AsyncExICYNotice(PChar(ICYGenre),
PChar(GetServerICYGenre(FICYHeader)));
GFFilterCallBack.AsyncExICYNotice(PChar(ICYURL),
PChar(GetServerICYURL(FICYHeader)));
GFFilterCallBack.AsyncExICYNotice(PChar(ICYBitrate),
PChar(GetServerICYBitRate(FICYHeader)));
end
else
begin
if not GetICYSuccessfullyConnected(FICYHeader, ErrMsg) then
showmessage('Can not receive the Stream.'#13#10#13#10 +
'Reason:'#13#10 + ErrMsg);
end;
// push the mp3 data to queue
if GFStringQueue <> nil then
GFStringQueue.Push(Temp);
if (not FMetadataEnabled) and (FMetaInterval = 0) then
begin
createFileNoMeataInt(FFileNoMetaData);
if FFileCreated and FRipStream then
Write(FFileObject, Temp);
end;
if FMetaInterval <> 0 then
begin
FMetaCount := length(Temp);
end;
// set header found state flag
FHeaderFound := true;
FMetaStartFound := false;
FTempSave := '';
FLock.UnLock;
exit;
end;
// if found and cutted the URLheader start to add mp3 data to the queue
if FHeaderFound then
begin
if FTempSave <> '' then
begin // completion of metadatablock is done here
TempSave := copy(FTempSave, 1, length(FTempSave));
Temp := copy(TempSave, 1, length(TempSave)) + copy(Temp, 1,
length(Temp));
FTempSave := '';
end;
Pos1 := Pos('StreamTitle', Temp);
if Pos1 <> 0 then
begin
CharO := (copy(Temp, Pos1 - 1, 1))[1];
LengthO := ((byte(CharO)) * 16);
if length(Temp) < Pos1 + LengthO - 1 then
begin
// found a incomlete metadata block
FTempSave := FTempSave + copy(Temp, 1, length(Temp));
FLock.UnLock;
exit;
end;
end;
if FMetaInterval <> 0 then
begin
FMetaCount := FMetaCount + length(Temp);
{ some servers send the first Metatag at a unspezified point! ,
so try to get the first sended Meta Info, and count the received
mp3 data }
Pos1 := Pos('StreamTitle', Temp);
if Pos1 <> 0 then
begin
Pos2 := length(Temp) - Pos1;
CharO := (copy(Temp, Pos1 - 1, 1))[1];
LengthO := ((byte(CharO)) * 16);
MetaString := copy(Temp, Pos1, LengthO - 1);
if MetaString <> '' then
begin
// MetaData Callback
if GFFilterCallBack <> nil then
begin
// parse stream Title & streamUrl
MetaTitle := getStreamTitle(MetaString);
MetaUrl := getStreamURl(MetaString);
// Stream MetaData Callback (parsed)
if length(MetaTitle) = 0 then
MetaTitle := 'N/A';
if length(MetaUrl) = 0 then
MetaUrl := 'N/A';
GFFilterCallBack.AsyncExMetaData(PChar(MetaTitle),
PChar(MetaUrl));
end;
FOutOfSync := false;
createNewFileIfNeeded(MetaString);
end;
// set the remaining data
Temp2 := copy(Temp, 0, Pos1 - 2);
Temp := Temp2 + copy(Temp, Pos1 - 1 + LengthO + 1, Pos2 - LengthO +
1);
// calculate the remaining mp3 data
FMetaCount := Pos2 - LengthO + 1;
if (GFStringQueue <> nil) and (not FOutOfSync) then
GFStringQueue.Push(Temp); // push the received mp3 data to the queue
if (FRipStream and FFileCreated and not FOutOfSync) then
Write(FFileObject, Temp);
FLock.UnLock;
exit;
end;
if FMetaCount > FMetaInterval then
begin
// calculate the start and end of the meta data in current block
Subi := FMetaCount - FMetaInterval;
Pos1 := length(Temp) - Subi + 1;
// get the length of the MetaData
CharO := (copy(Temp, Pos1, 1))[1];
LengthO := ((byte(CharO)) * 16);
if length(Temp) < Pos1 + LengthO - 1 then
begin
// found a incomlete metadata block
FTempSave := FTempSave + copy(Temp, 1, length(Temp));
FLock.UnLock;
exit;
end;
if LengthO <> 0 then
if Pos('Stream', MetaString) = 0 then
begin
// Server is out of Sync.!
if GFFilterCallBack <> nil then
// >ToDO: error callback
GFFilterCallBack.AsyncExMetaData('Server is out of sync, trying to resync', 'Server is out of sync, trying to resync');
FOutOfSync := true;
FLock.UnLock;
exit;
end;
MetaString := copy(Temp, Pos1, LengthO);
if MetaString <> '' then
begin // a metastring has been found
if GFFilterCallBack <> nil then
begin
// parse stream Title & streamUrl
MetaTitle := getStreamTitle(MetaString);
MetaUrl := getStreamURl(MetaString);
// Stream MetaData Callback (parsed)
if length(MetaTitle) = 0 then
MetaTitle := 'N/A';
if length(MetaUrl) = 0 then
MetaUrl := 'N/A';
GFFilterCallBack.AsyncExMetaData(PChar(MetaTitle), PChar(MetaUrl));
end;
if not (FOutOfSync) then
createNewFileIfNeeded(MetaString);
end;
// set the remaining data
Temp2 := copy(Temp, 0, Pos1 - 1);
Temp := Temp2 + copy(Temp, Pos1 + LengthO + 1, Subi - LengthO - 1);
// calculate the remaining mp3 data
FMetaCount := Subi - LengthO - 1
end;
end;
if (GFStringQueue <> nil) and (not FOutOfSync) then
GFStringQueue.Push(Temp); // pop the received mp3 data to the queue
// file ripper feature
if (not FMetadataEnabled) and (FMetaInterval = 0) then
createFileNoMeataInt(FFileNoMetaData);
if (FRipStream) and (FFileCreated) and (not FOutOfSync) then
Write(FFileObject, Temp);
end;
FLock.UnLock;
except
FLock.UnLock;
// no exception handling at present :(
// during prebuffering and during minimizing the app an exception is thrown:
// -> nil pointer acces
end;
end;
procedure TShoutcastStream.OnSockConnect(Sender: TObject);
begin
FLock.Lock;
if FMetadataEnabled then
// send the official connect string (metadata)
FSock.Send('GET ' + FLocation + ' HTTP/1.0'#13#10
+ 'User-Agent: DSPlayer'#13#10
+ 'Host: '#13#10
+ 'icy-MetaData:1'#13#10#13#10)
else
// send the official connect string (no metadata)
FSock.Send('GET ' + FLocation + ' HTTP/1.0'#13#10
+ 'User-Agent: DSPlayer'#13#10
+ 'Host: '#13#10#13#10#13#10);
FLock.UnLock;
end;
procedure TShoutcastStream.SetConnectToIP(Adress: string; Port: string;
Location: string; Meta: boolean);
begin
FLock.Lock;
FMetadataEnabled := Meta;
FSock.HostName := Adress;
FSock.PortName := Port;
FLocation := Location;
FSock.Connected := true;
FLock.UnLock;
end;
procedure TShoutcastStream.OnSockInfo(Sender: TObject; SocketInfo: TSocketInfo;
Msg: string);
begin
FLock.Lock;
FApplication.ProcessMessages;
if SocketInfo = siError then
begin
GFExit := true;
// Error Handling
//..
// Somtimes when we connect to a still well connected Adress
// the sock api is a little slow and needs some time to free the
// used address. -> error WSAEADDRINUSE
if Assigned(GFFilterCallBack) then
GFFilterCallBack.AsyncExSockError(PChar(Msg))
else
ShowMessage(Msg);
end;
FLock.UnLock;
end;
constructor TShoutcastStream.Create;
begin
FMetadataEnabled := true;
FMetaCount := 0;
FMetaInterval := 0;
FFile := '';
FRipStream := false;
FFileCreated := false;
FLock := TBCCritSec.Create;
FReceiveForm := TForm.Create(nil);
FReceiveForm.Hide;
FSock := TSock.Create(FReceiveForm);
FSock.OnConnect := OnSockConnect;
FSock.OnInfo := OnSockInfo;
FSock.OnRead := OnSockRead;
FHeaderFound := false;
FOutOfSync := false;
FTempSave := '';
FFileNoMetaData := '';
FApplication := TApplication.Create(nil);
FICYHeader := 'No Header aviailble at present';
end;
destructor TShoutcastStream.Destroy;
var
Application: TApplication;
begin
FLock.Lock;
Application := TApplication.Create(nil);
FApplication.Destroy;
if FFileCreated then
CloseFile(FFileObject);
FSock.Destroy; // buggy, if detroy is called Sock Adress might be still in use
Application.Destroy;
FReceiveForm.Free;
FLock.UnLock;
FLock.Free;
inherited Destroy;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -