Author Topic: Streaming encoder with 2 sound cards  (Read 2725 times)

Laura27

  • Posts: 11
Streaming encoder with 2 sound cards
« on: 6 Aug '10 - 14:41 »
Hi,  :)

Sorry if I'm a newbie.
I'm looking to develop a small shoutcast encoder for my radio station.
I'm using demo CAST program and it works great (I'm developing using Visaul Basic 6).

I've implemented ACCplus and it works.

My need is this: the encoder is on a pc with two sound cards and in some moments I need to change the input sound card for the encoder.
The are sono hours of the day that I have to stream the audio from audio card1 , and other part of the day I have to stream the audio coming from the second card.

I've see some examples but it's not clear to me how to change the audio card for the encoder.
I know this is a generic question, but any help will be very appreciated.

Thanks and sorry for my poor English.

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #1 on: 6 Aug '10 - 15:48 »
An encoder can be moved from one BASS channel to another with the BASS_Encode_SetChannel function. In your case, when you want to switch devices, you would create a recording channel on the new device and then move the encoder to it (and then free the old recording channel).

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #2 on: 6 Aug '10 - 16:45 »
Ian,

thanks for your quick answer.
May I create the record channel on both devices at the startup (load form in vb) and then move the encoder or I must create the new and free the old channel everytime I move the encoder?
During the weekend I'll try to implement your solution.

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #3 on: 6 Aug '10 - 17:31 »
Yes, pre-creating both of the recording channels and moving the encoder between them should be fine too. There will always be 1 unnecessary recording channel that way though, so it is a bit inefficient, but it shouldn't be too much so :)

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #4 on: 7 Aug '10 - 15:29 »
Hi Ian,

I'm working over my encoder.
My pc has got a phisical sound card and I've added a virutal audio card (both cards are working, windows set 0 for the phisical card and 3 for the virtual).
I've tried to create the record channel on both devices with this code:

    If (BASS_RecordInit(3) = 0) Then
         Call Error_("Can't initialize virtual card")
         End
    End If
    If (BASS_RecordInit(1) = 0) Then
        Call Error_("Can't initialize phisical card")
        End
    End If


then I've tried to use BASS_Encode_SetChannel function, but to me it's not so clear how to use it.
I don't understand what I have to set for handle and channel parameters.

I've tried another way using BASS_RecordSetDevice: it  works but only when the encoder is stopped, once is started to change the record device has no effect.
So I understand I have to use BASS_Encode_SetChannel  :)

Please, could you show me an example to show me how to use it?
I really thank you.

Laura

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #5 on: 8 Aug '10 - 12:20 »
Sunday morning working on my project  :)

I've seen some posts on the forum and some help on the documentation, so I hope to have seen the right way to create my software.
I was thinking to use 2 sound cards for my needs, but I've seen that I can use just one card.

I have to stream live events using the line_in from the audio cards, but in some hours of the day we have to stream some mp3 files (a recorded audio).
So I've tried in this way:

1. setup the default record device
    Dim live_source As Long
    live_source = BASS_RecordInit(-1)


2. init the card for the player and I create the stream for the mp3 file
    If BASS_Init(-1, 44100, 0, Me.hwnd, 0) = BASSFALSE Then
        Call Error_("Can't initialize digital sound system")
        End
    End If
    playback_Handle = BASS_StreamCreateFile(BASSFALSE, StrPtr("c:\temp\demo.mp3"), 0, 0, 0)



3. when the start encoder button is pressed I start recording @ 44100hz 16-bit stereo (paused to setup encoder first)
    rchan = BASS_RecordStart(44100, 2, BASS_RECORD_PAUSE, AddressOf RecordingCallback, 0)

4. then I start the encoder
    encoder = BASS_Encode_Start(rchan, com, BASS_ENCODE_NOHEAD Or BASS_ENCODE_AUTOFREE, 0, 0)

5. and a resume to record
    Call BASS_ChannelPlay(rchan, False)

Everything here works, the encoder streams the live_source to the shoutcast server (major part of the code is taken from cast example).

Now the second part.
I've created 2 buttons on the form: button1 is to play the mp3 file and stream it instead of the live_source, button2 is to come back to the live_source stopping the mp3 file.
So this is the code when I press button1:

    Dim debug_1 As Boolean
    Dim debug_2 As Boolean
    debug_1 = BASS_ChannelPlay(playback_Handle, BASSFALSE)
    debug_2 = BASS_Encode_SetChannel(encoder, playback_Handle)
    MsgBox (debug_1 & " " & debug_2 & " " & playback_Handle)


the msgbox result is "true" "true" "-1342177279" and the switch operation works! :)

But now the problem: how to come back to the live_source?
This is the code for button2:

    Dim debug_3 As Boolean
    debug_3 = BASS_Encode_SetChannel(encoder, rchan)
    MsgBox (debug_3 & " " & rchan)


the msgbox result is "false" "-2147483646" and it doesn't work :(
I was quite sure to use rchan to switch to the live_source, but it's wrong: why?

Another question: how can I stop the mp3 file that is playing?
If I use:
   Call BASS_ChannelStop(playback_Handle)
then encoder stops.

Thanks for any help.

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #6 on: 9 Aug '10 - 14:47 »
    Dim debug_3 As Boolean
    debug_3 = BASS_Encode_SetChannel(encoder, rchan)
    MsgBox (debug_3 & " " & rchan)


the msgbox result is "false" "-2147483646" and it doesn't work :(
I was quite sure to use rchan to switch to the live_source, but it's wrong: why?

To find out what's wrong, please use BASS_ErrorGetCode to check the error code generated by the failed BASS_Encode_SetChannel call.

Another question: how can I stop the mp3 file that is playing?
If I use:
   Call BASS_ChannelStop(playback_Handle)
then encoder stops.

That is the correct way to stop the stream, but if the encoder is set on the stream, then it will stop receiving data too. Do you want the encoder to receive silence while the stream is stopped?

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #7 on: 9 Aug '10 - 15:07 »
Hi Ian, thanks for your help  :)

I get error 5 BASS_ERROR_HANDLE when I call debug_3 = BASS_Encode_SetChannel(encoder, rchan)

Second point: I want to stop the mp3 file playing right after I've switched to the live stream, so I send to the shoutcast server the live stream
My idea is: normally the CAST software send the audio coming from the line_in on my sound card, but when I click a button I want to play some mp3 files and the the audio to the shoutcast server instaed of the line_in audio.
Clicking a second button I want to come back to send the line_in audio to the server and I want to stop the mp3 play.

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #8 on: 9 Aug '10 - 17:32 »
I get error 5 BASS_ERROR_HANDLE when I call debug_3 = BASS_Encode_SetChannel(encoder, rchan)

That means at least one of the "encoder" or "rchan" handles is invalid. Did you happen to call BASS_ChannelStop on the recording channel ("rchan") when you moved the encoder to the MP3 stream? That would free the recording channel, which you don't want. You could use BASS_ChannelPause instead.

Another possibility is that the RECORDPROC is returning FALSE, which would also result in the recording channel being freed. It should simply "return TRUE".

Second point: I want to stop the mp3 file playing right after I've switched to the live stream, so I send to the shoutcast server the live stream
My idea is: normally the CAST software send the audio coming from the line_in on my sound card, but when I click a button I want to play some mp3 files and the the audio to the shoutcast server instaed of the line_in audio.
Clicking a second button I want to come back to send the line_in audio to the server and I want to stop the mp3 play.

OK, that sounds like everything should be fine once the BASS_ERROR_HANDLE problem is sorted then :)

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #9 on: 10 Aug '10 - 11:45 »
Hi Ian,

I've solved the problem with error 5, wrong handle: switching back to the line_in audio I was sending a Bass_ChannelStop to stop the mp3 file.
I use Bass_ChannelPause and it's fine.

Now I can stream to internet the audio coming from the line_in audio card and pressing a button the program starts playing an mp3 file sending the mp3 audio to the shoutcast server instead of the line_in audio.
Pressing again the button line_in audio comes back to the shoutcast server: great!

But now I need to play more than one mp3 file.
So, I've loaded in an array a playlist of mp3 files, when I switch to the mp3 file I play the first location of the array and I activate a timer routine to check if the file is finished.
If the file is finished I start to play the next element of the array.
Then i loop around all the elements of the array: I stop this routine when switch button is pressed again to come back to the line_in audio.
The mp3 play loop works fine, but after the first mp3 file is played the encoder stops sending data to the shoutcast server.

This is the code when I press the switch button from line_in to mp3 file:

    mp3_index = 0
    playback_Handle = BASS_StreamCreateFile(BASSFALSE, StrPtr(mp3_files(mp3_index)), 0, 0, 0)
    call BASS_ChannelPlay(playback_Handle, BASSFALSE)
    call BASS_Encode_SetChannel(encoder, playback_Handle)


mp3 file is played and the encoder is sending the data to the shoutcast server
The next instruction is:

     mp3_timer.Enabled = True

to enable the routine to play the next file at the end of the current
And this is the routine:

    If BASS_ChannelGetPosition(playback_Handle, BASS_POS_BYTE) >= BASS_ChannelGetLength(playback_Handle, BASS_POS_BYTE) Then
        mp3_index = mp3_index + 1
        If mp3_index > 2 Then 'is limited to 3 elements for testing pourpose
            mp3_index = 0
        End If
        playback_Handle = BASS_StreamCreateFile(BASSFALSE, StrPtr(mp3_files(mp3_index)), 0, 0, 0)
        Call BASS_ChannelPlay(playback_Handle, BASSFALSE)
    End If


I check the length of the file and the current position to see if the file is finished.
I think that I'm doing something wrong and the encoder die, but I don't know what :(

And, do I have to free the stream before to proceed with the next file?
Thanks again :)

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #10 on: 10 Aug '10 - 13:53 »
Are you freeing the old stream before moving the encoder to the new stream? If so, that would result in the encoder being freed too, due to the BASS_ENCODE_AUTOFREE flag in the BASS_Encode_Start call. So, if you are currently doing that, you could try removing the BASS_ENCODE_AUTOFREE flag or waiting until after the encoder has been moved to the new stream before freeing the old stream.

Another little improvement that you could make is to replace the timer with a BASS_SYNC_END sync (see BASS_ChannelSetSync), which will inform you of when the stream reaches the end.

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #11 on: 10 Aug '10 - 15:09 »
Ian,

with your help I've found my problem: when it was time for the second mp3 file I didn't written the setchannel command:
        playback_Handle = BASS_StreamCreateFile(....
        Call BASS_ChannelPlay(playback_Handle, BASSFALSE)

        Call BASS_Encode_SetChannel(encoder, playback_Handle)

Now it's working fine :)
I'm very sorry because everytime I place a new question, but I'm not able to make working BASS_ChannelSetSync: everytime it raises the function immediately and not at the end of the stream.
This is my code:

    playback_Handle = BASS_StreamCreateFile(BASSFALSE, StrPtr(mp3_files(mp3_index)), 0, 0, 0)
    Call BASS_ChannelPlay(playback_Handle, BASSFALSE)
    Call BASS_ChannelSetSync(playback_Handle, BASS_SYNC_END, 0, test(), 0)
    CAll BASS_Encode_SetChannel(encoder, playback_Handle)


test() function is a msgbox popup and it appears immediately at the execution of the call: what's wrong with it?

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #12 on: 10 Aug '10 - 16:30 »
I think the problem there is the "test()" in the BASS_ChannelSetSync call, ie. the "test" function is being called and its return value passed to BASS_ChannelSetSync. It should probably look like this...

Code: [Select]
Call BASS_ChannelSetSync(playback_Handle, BASS_SYNC_END, 0, AddressOf test, 0)

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #13 on: 11 Aug '10 - 13:13 »
Hi Ian,

I'm trying to use the Call BASS_ChannelSetSync but I'm not able to use the command AddressOf:

    Call BASS_ChannelSetSync(playback_Handle, BASS_SYNC_END, 0, AddressOf test, 0)

VB always says that I have an error in the use of the AddressOf operator.
I've looked on some posts and on some vb tutorials, but I don't understand how to use it.

Anyway all the things are working fine, I've implemented an ID3v1 reading function using BASS_ChannelGetTags :)

I thank you for your help and your patience with me, and I thanks all the guys writing on this forum: I've found great help.

Now I've to check the aac+ encoder because seems to stream always at 96k with 88Khz, but in case of need I'll open another post (before I want to check the forum to see if someone have found the same problem).

Thanks!

Laura

Ian @ un4seen

  • Administrator
  • Posts: 20768
Re: Streaming encoder with 2 sound cards
« Reply #14 on: 11 Aug '10 - 16:23 »
I'm not a VB user myself, so I'm afraid I can't give definitive advice on that, but looking at the VB examples in the BASS package, they are using "AddressOf" in their BASS_ChannelSetSync calls. Another thing I've noticed is that the callback functions are always in a separate "mod..." file, so perhaps that's the secret :)

(: JOBnik! :)

  • Posts: 1066
Re: Streaming encoder with 2 sound cards
« Reply #15 on: 11 Aug '10 - 17:03 »
Hi ;D

Don't forget to use the same SYNCPROC params and their type:

Code: [Select]
Sub SYNCPROC(ByVal handle As Long, ByVal channel As Long, ByVal data As Long, ByVal user As Long)
   
    'CALLBACK FUNCTION !!!
   
    'Similarly in here, write what to do when sync function
    'is called, i.e screen flash etc.
   
    ' NOTE: a sync callback function should be very quick as other
    ' syncs cannot be processed until it has finished.
    ' handle : The sync that has occured
    ' channel: Channel that the sync occured in
    ' data   : Additional data associated with the sync's occurance
    ' user   : The 'user' parameter given when calling BASS_ChannelSetSync */
   
End Sub

Rename the SYNCPROC sub to, e.g: Test
As Ian wrote, the callback functions should be in a Module and you call them by their address, i.e: AddressOf Test

Check the Memory example in VB directory for usage of BASS_SYNC_END

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #16 on: 13 Aug '10 - 08:33 »
Thanks guys, you're right!
The solutions is to put the callback function on an external module.  :)

But now I've another problem :(
I need to use an array on the callback function and I don't know how to pass the array to the function.
If I declare Public the array VB returns a compile error saying that I can't do it.
I've tryed to pass the array using the user field in the BASS_ChannelSetSync, but it can be only a long variable.
At the moment the only solution is: the callback function call a sub on the main module that see the array declared with a DIM command at the beginnig of the module.
Not so elegant, but it works.

Laura

Laura27

  • Posts: 11
Re: Streaming encoder with 2 sound cards
« Reply #17 on: 13 Aug '10 - 08:37 »
opss :)
I've found how to solve it: I have to declare the array on a nodule and not on a form.

thanks again

Laura