-2

I have a mp3 player in Delphi. When the player is running and I change the audio output device, say from line out (speakers) to bluetooth, the player still "sends" the sound to the line out device. When my bluetooth headset is connected and I start the player, everything is fine and the player "sends" the sound to the bluetooth device. But when I disconnect the bluetooth speakers/headset, the player doesn't play any song, it just skips every song as they won't be "playable".

Is there a way to get this managed? Every other player, VLC, Winamp, Windows Media Player, are able to handle the change of the output device "on the fly".

For the player I use Delphi XE, but I think this isn't relevant to the problem as itself. At the time I use BASS library 2.4.11

Thanks for your answers in advance! MPage

  • Pause the playback, set the device, start the playback (you can find the newly selected default device by enumerating device info). – Victoria Nov 18 '17 at 15:04
  • @Victoria It would be very appreciated if you could show me a sample for enumerating and setting the output device(s). :-) Many thanks in advance! – XingFu ZhuanYun Nov 18 '17 at 18:44

2 Answers2

0

Yes, there is the way.

AIMP player is exactly written in Delphi using BASS library.

If you stop playing, change audio output in preferences and start playing - it sends music to the newly selected sound device.

Arioch 'The
  • 15,005
  • 31
  • 59
  • @Victoria "the player doesn't play any song, it just skips every song" - you may try to guess what guy meant and even develop the player for him, but as of now he did not asked for it, did not presented his code, did not reported specific error and position - nothing that common sense and SE rules require. ( PS: there is also `SetChannelDevice` function, additionally one can make virtual channels decoupling input unpacking and output sinks management, you can develop an example for him if you want ) – Arioch 'The Nov 18 '17 at 15:07
  • Thank you both for your answers! @Arioch 'The I didn't "present" code as there is no error. The reason why the player skips the files is when the output device is not available. So, if I can implement a "device output change function", everything will be fine then. And yes, out of your answers I can see, that it is possible. :-) I never had to change the output device yet. Now I see, that I need a routine to scan and set the output device. MPage – XingFu ZhuanYun Nov 18 '17 at 18:57
  • @XingFuZhuanYun It doesn't matter if there's no error. You said your code does not work as you expect: show your code so that people might be able to tell you whether or not there's something wrong with it, or an alternative. – Dave Nottage Nov 18 '17 at 20:26
  • @Dave Nottage I didn't say may code doesn't work as expected. From the answers of Victoria and Arioch 'The I can read that I need a procedure to enumerate the output devices and set the device to the active output device. At this time, I don't have such a function/procedure. "Anything else" works pretty fine. – XingFu ZhuanYun Nov 18 '17 at 21:51
  • @XingFuZhuanYun Your question states: "But when I disconnect the bluetooth speakers/headset, the player doesn't play any song, it just skips every song as they won't be "playable", i.e. the code is not doing what you want. That may be because of something wrong in your code, including something you may have missed. It's impossible to tell that because you're not posting any code – Dave Nottage Nov 19 '17 at 05:45
0

So, after reading some manuals and doing some test, this is what I have now in my "MediaPause" routine:

// Reset counter
i := 1;

// Reset device list
lstADevices.Clear;

while BASS_GetDeviceInfo(i, ADeviceInfo) do
begin
  lstADevices.Add(ADeviceInfo.name);
  inc(i);

end;

intDevice := -1;

for i := 0 to lstADevices.Count - 1 do
begin
  if lstADevices[i] = 'Bluetooth A2DP Stereo Audio (Bose AE2w 01.02.00( Stereo ))' then
  begin
    intDevice := i + 1; // + 1 is important, because the list starts with 0! (for BASS 0 means 'no device')
    BASS_GetDeviceInfo(intDevice, ADeviceInfo);
    intFlag := ADeviceInfo.flags;

    if intFlag = 67108868 then
    begin
      for j := 0 to lstADevices.Count - 1 do
      begin
        if lstADevices[j] = 'Speakers (Realtek High Definition Audio)' then
        begin
          intDevice := j + 1; // The list starts at 0
          break;

        end;

      end;

    end;

    break;

  end;

end;

BASS_Init(intDevice, 44100, 0, Application.Handle, nil);
blnBASS := BASS_ChannelSetDevice(AudioStream, intDevice);

if not blnBASS then
  intBASSErrorCode := BASS_ErrorGetCode;

BASS_ChannelPlay(AudioStream, False);

When the program is started and the bluetooth headset is not connected, it will not be enumerated to get into the device list. So I have to enumerate the devices at any necessary time. I wanted to implement this into the "tick counter" for displaying the time (ticks in seconds), but because of the following behavior I didn't do so yet. I can switch (BASS_ChannelSetDevice) between the bluetooth headset and the speakers once. When I want/have to switch again, to whatever reason, I get the error code 4 which means BASS_ERROR_BUFLOST (The sample buffer was lost). I tried to find anything according the buffer size, but couldn't find anything.

I check the flag value 67108868 of the bluetooth device, because I couldn't find any other way to check if the device is available or not. If the bluetooth device has been connected once during the runtime, it will always get enumerated even it is disconnected afterwards. It also has the "enabled" state, so I only found the difference in the flag value. Packing the above code into the tick counter for the display I could get it managed to change the devices from speakers to headset automatically, which would be the "perfect" way for me, but due to the problem with the "buffer lost" error, I removed it from the tick counter routine.

Like Victoria and Arioch 'The mentioned, I paused the player before changing the device. Like mentioned, it works one time and the next time I run into the "buffer lost" error. This means, there is no error produced, but the output isn't changed then.

As I'm not sure if "my way" is correct in any sense, is there a "more safe" way to change the devices?

MPage

  • I could find something according the buffer and included this line into my code: BASS_SetConfig(BASS_CONFIG_BUFFER, 5000); But, like before, I can change the device just once. Then I run into the "buffer lost" situation again. – XingFu ZhuanYun Nov 20 '17 at 19:11