1812fde99SAxel Dörfler /* 2812fde99SAxel Dörfler * Copyright 2002-2009, Haiku. 3812fde99SAxel Dörfler * Distributed under the terms of the MIT License. 4812fde99SAxel Dörfler * 5812fde99SAxel Dörfler * Authors: 6812fde99SAxel Dörfler * Marcus Overhagen 7812fde99SAxel Dörfler * Jérôme Duval 8812fde99SAxel Dörfler */ 9812fde99SAxel Dörfler 10812fde99SAxel Dörfler 11812fde99SAxel Dörfler #include <SoundPlayer.h> 12812fde99SAxel Dörfler 1352a38012Sejakowatz #include <math.h> 142386ff94SIngo Weinhold #include <string.h> 1552a38012Sejakowatz 16812fde99SAxel Dörfler #include <Autolock.h> 17812fde99SAxel Dörfler #include <MediaRoster.h> 18812fde99SAxel Dörfler #include <ParameterWeb.h> 19812fde99SAxel Dörfler #include <Sound.h> 20812fde99SAxel Dörfler #include <TimeSource.h> 21812fde99SAxel Dörfler 2252a38012Sejakowatz #include "SoundPlayNode.h" 23812fde99SAxel Dörfler 24812fde99SAxel Dörfler #include "debug.h" 2552a38012Sejakowatz 26df42a7b5Sbeveloper 27d6105cedSbeveloper // Flags used internally in BSoundPlayer 28d6105cedSbeveloper enum { 29df42a7b5Sbeveloper F_NODES_CONNECTED = (1 << 0), 30df42a7b5Sbeveloper F_HAS_DATA = (1 << 1), 31df42a7b5Sbeveloper F_IS_STARTED = (1 << 2), 32df42a7b5Sbeveloper F_MUST_RELEASE_MIXER = (1 << 3), 33d6105cedSbeveloper }; 34d6105cedSbeveloper 3552a38012Sejakowatz 369b9aa75aSMichael Lotz static BSoundPlayer::play_id sCurrentPlayID = 1; 379b9aa75aSMichael Lotz 389b9aa75aSMichael Lotz 39812fde99SAxel Dörfler BSoundPlayer::BSoundPlayer(const char* name, BufferPlayerFunc playerFunction, 40812fde99SAxel Dörfler EventNotifierFunc eventNotifierFunction, void* cookie) 4152a38012Sejakowatz { 4252a38012Sejakowatz CALLED(); 43df42a7b5Sbeveloper 4440c2c00aSbeveloper TRACE("BSoundPlayer::BSoundPlayer: default constructor used\n"); 45df42a7b5Sbeveloper 46812fde99SAxel Dörfler media_multi_audio_format format = media_multi_audio_format::wildcard; 4740c2c00aSbeveloper 48812fde99SAxel Dörfler _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction, 49812fde99SAxel Dörfler cookie); 5052a38012Sejakowatz } 5152a38012Sejakowatz 52df42a7b5Sbeveloper 53812fde99SAxel Dörfler BSoundPlayer::BSoundPlayer(const media_raw_audio_format* _format, 54812fde99SAxel Dörfler const char* name, BufferPlayerFunc playerFunction, 55812fde99SAxel Dörfler EventNotifierFunc eventNotifierFunction, void* cookie) 5652a38012Sejakowatz { 5752a38012Sejakowatz CALLED(); 58df42a7b5Sbeveloper 5940c2c00aSbeveloper TRACE("BSoundPlayer::BSoundPlayer: raw audio format constructor used\n"); 60df42a7b5Sbeveloper 61812fde99SAxel Dörfler media_multi_audio_format format = media_multi_audio_format::wildcard; 62812fde99SAxel Dörfler *(media_raw_audio_format*)&format = *_format; 6340c2c00aSbeveloper 6440c2c00aSbeveloper #if DEBUG > 0 6540c2c00aSbeveloper char buf[100]; 66812fde99SAxel Dörfler media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = format; 6740c2c00aSbeveloper string_for_format(tmp, buf, sizeof(buf)); 6840c2c00aSbeveloper TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf); 6940c2c00aSbeveloper #endif 7040c2c00aSbeveloper 71812fde99SAxel Dörfler _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction, 72812fde99SAxel Dörfler cookie); 7352a38012Sejakowatz } 7452a38012Sejakowatz 75df42a7b5Sbeveloper 7652a38012Sejakowatz BSoundPlayer::BSoundPlayer(const media_node& toNode, 77812fde99SAxel Dörfler const media_multi_audio_format* format, const char* name, 78812fde99SAxel Dörfler const media_input* input, BufferPlayerFunc playerFunction, 79812fde99SAxel Dörfler EventNotifierFunc eventNotifierFunction, void* cookie) 8052a38012Sejakowatz { 8152a38012Sejakowatz CALLED(); 82df42a7b5Sbeveloper 8340c2c00aSbeveloper TRACE("BSoundPlayer::BSoundPlayer: multi audio format constructor used\n"); 84df42a7b5Sbeveloper 859490cc05SMichael Lotz if ((toNode.kind & B_BUFFER_CONSUMER) == 0) 8652a38012Sejakowatz debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n"); 87df42a7b5Sbeveloper 8840c2c00aSbeveloper #if DEBUG > 0 8940c2c00aSbeveloper char buf[100]; 9040c2c00aSbeveloper media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = *format; 9140c2c00aSbeveloper string_for_format(tmp, buf, sizeof(buf)); 9240c2c00aSbeveloper TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf); 9340c2c00aSbeveloper #endif 9440c2c00aSbeveloper 95812fde99SAxel Dörfler _Init(&toNode, format, name, input, playerFunction, eventNotifierFunction, 96812fde99SAxel Dörfler cookie); 9752a38012Sejakowatz } 9852a38012Sejakowatz 99df42a7b5Sbeveloper 10052a38012Sejakowatz BSoundPlayer::~BSoundPlayer() 10152a38012Sejakowatz { 10252a38012Sejakowatz CALLED(); 103d6105cedSbeveloper 104812fde99SAxel Dörfler if ((fFlags & F_IS_STARTED) != 0) { 105812fde99SAxel Dörfler // block, but don't flush 106812fde99SAxel Dörfler Stop(true, false); 107df42a7b5Sbeveloper } 108d6105cedSbeveloper 109df42a7b5Sbeveloper status_t err; 11095531d1eSJérôme Duval BMediaRoster* roster = BMediaRoster::Roster(); 111812fde99SAxel Dörfler if (roster == NULL) { 11295531d1eSJérôme Duval TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n"); 113df42a7b5Sbeveloper goto cleanup; 114df42a7b5Sbeveloper } 11595531d1eSJérôme Duval 116812fde99SAxel Dörfler if ((fFlags & F_NODES_CONNECTED) != 0) { 117812fde99SAxel Dörfler // Ordinarily we'd stop *all* of the nodes in the chain before 118812fde99SAxel Dörfler // disconnecting. However, our node is already stopped, and we can't 119812fde99SAxel Dörfler // stop the System Mixer. 120812fde99SAxel Dörfler // So, we just disconnect from it, and release our references to the 121812fde99SAxel Dörfler // nodes that we're using. We *are* supposed to do that even for global 122812fde99SAxel Dörfler // nodes like the Mixer. 12375daf556SMarcus Overhagen err = roster->Disconnect(fMediaOutput, fMediaInput); 124812fde99SAxel Dörfler if (err != B_OK) { 125812fde99SAxel Dörfler TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: " 126812fde99SAxel Dörfler "%ld (%s)\n", err, strerror(err)); 12795531d1eSJérôme Duval } 128df42a7b5Sbeveloper } 12995531d1eSJérôme Duval 130812fde99SAxel Dörfler if ((fFlags & F_MUST_RELEASE_MIXER) != 0) { 131df42a7b5Sbeveloper // Release the mixer as it was acquired 132df42a7b5Sbeveloper // through BMediaRoster::GetAudioMixer() 133d6105cedSbeveloper err = roster->ReleaseNode(fMediaInput.node); 134812fde99SAxel Dörfler if (err != B_OK) { 135812fde99SAxel Dörfler TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: " 136812fde99SAxel Dörfler "%ld (%s)\n", err, strerror(err)); 137df42a7b5Sbeveloper } 13895531d1eSJérôme Duval } 13995531d1eSJérôme Duval 140df42a7b5Sbeveloper cleanup: 141df42a7b5Sbeveloper // Dispose of the player node 142812fde99SAxel Dörfler 143df42a7b5Sbeveloper // We do not call BMediaRoster::ReleaseNode(), since 144df42a7b5Sbeveloper // the player was created by using "new". We could 145df42a7b5Sbeveloper // call BMediaRoster::UnregisterNode(), but this is 146*f1059fbdSDario Casalinuovo // supposed to be done by BMediaNode destructor automatically. 147*f1059fbdSDario Casalinuovo 148*f1059fbdSDario Casalinuovo // The node is deleted by the Release() when ref count reach 0. 149*f1059fbdSDario Casalinuovo // Since we are the sole owners, and no one acquired it 150*f1059fbdSDario Casalinuovo // this should be the case. The Quit() synchronization 151*f1059fbdSDario Casalinuovo // is handled by the DeleteHook inheritance. 152*f1059fbdSDario Casalinuovo // NOTE: this might be crucial when using a BMediaEventLooper. 153*f1059fbdSDario Casalinuovo if (fPlayerNode->Release() != NULL) { 154*f1059fbdSDario Casalinuovo TRACE("BSoundPlayer::~BSoundPlayer: Error the producer node " 155*f1059fbdSDario Casalinuovo "appears to be acquired by someone else than us!"); 156*f1059fbdSDario Casalinuovo } 157d6105cedSbeveloper 158812fde99SAxel Dörfler // do not delete fVolumeSlider, it belongs to the parameter web 159d6105cedSbeveloper delete fParameterWeb; 16052a38012Sejakowatz } 16152a38012Sejakowatz 16252a38012Sejakowatz 16352a38012Sejakowatz status_t 16452a38012Sejakowatz BSoundPlayer::InitCheck() 16552a38012Sejakowatz { 16652a38012Sejakowatz CALLED(); 167d6105cedSbeveloper return fInitStatus; 16852a38012Sejakowatz } 16952a38012Sejakowatz 17052a38012Sejakowatz 17152a38012Sejakowatz media_raw_audio_format 17252a38012Sejakowatz BSoundPlayer::Format() const 17352a38012Sejakowatz { 17452a38012Sejakowatz CALLED(); 17552a38012Sejakowatz 176df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 177df42a7b5Sbeveloper return media_raw_audio_format::wildcard; 178df42a7b5Sbeveloper 179df42a7b5Sbeveloper return fPlayerNode->Format(); 18052a38012Sejakowatz } 18152a38012Sejakowatz 18252a38012Sejakowatz 18352a38012Sejakowatz status_t 18452a38012Sejakowatz BSoundPlayer::Start() 18552a38012Sejakowatz { 18652a38012Sejakowatz CALLED(); 18752a38012Sejakowatz 188df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 189df42a7b5Sbeveloper return B_NO_INIT; 190df42a7b5Sbeveloper 191812fde99SAxel Dörfler if ((fFlags & F_IS_STARTED) != 0) 192df42a7b5Sbeveloper return B_OK; 19352a38012Sejakowatz 19495531d1eSJérôme Duval BMediaRoster* roster = BMediaRoster::Roster(); 19595531d1eSJérôme Duval if (!roster) { 19695531d1eSJérôme Duval TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n"); 19795531d1eSJérôme Duval return B_ERROR; 19895531d1eSJérôme Duval } 19995531d1eSJérôme Duval 20095096991SJérôme Duval if (!fPlayerNode->TimeSource()->IsRunning()) { 20195096991SJérôme Duval roster->StartTimeSource(fPlayerNode->TimeSource()->Node(), 20295096991SJérôme Duval fPlayerNode->TimeSource()->RealTime()); 20395096991SJérôme Duval } 20495096991SJérôme Duval 205df42a7b5Sbeveloper // Add latency and a few ms to the nodes current time to 206df42a7b5Sbeveloper // make sure that we give the producer enough time to run 207df42a7b5Sbeveloper // buffers through the node chain, otherwise it'll start 208df42a7b5Sbeveloper // up already late 20995531d1eSJérôme Duval 210812fde99SAxel Dörfler status_t err = roster->StartNode(fPlayerNode->Node(), 211812fde99SAxel Dörfler fPlayerNode->TimeSource()->Now() + Latency() + 5000); 212df42a7b5Sbeveloper if (err != B_OK) { 213df42a7b5Sbeveloper TRACE("BSoundPlayer::Start: StartNode failed, %ld", err); 21495531d1eSJérôme Duval return err; 21552a38012Sejakowatz } 21652a38012Sejakowatz 217812fde99SAxel Dörfler if (fNotifierFunc != NULL) 21895096991SJérôme Duval fNotifierFunc(fCookie, B_STARTED, this); 21995096991SJérôme Duval 22095096991SJérôme Duval SetHasData(true); 221df42a7b5Sbeveloper atomic_or(&fFlags, F_IS_STARTED); 222df42a7b5Sbeveloper 223df42a7b5Sbeveloper return B_OK; 224df42a7b5Sbeveloper } 225df42a7b5Sbeveloper 22652a38012Sejakowatz 22752a38012Sejakowatz void 228812fde99SAxel Dörfler BSoundPlayer::Stop(bool block, bool flush) 22952a38012Sejakowatz { 23052a38012Sejakowatz CALLED(); 23152a38012Sejakowatz 232df42a7b5Sbeveloper TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush); 233df42a7b5Sbeveloper 234df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 23552a38012Sejakowatz return; 23652a38012Sejakowatz 237812fde99SAxel Dörfler // TODO: flush is ignored 238a0703a47Sbeveloper 239812fde99SAxel Dörfler if ((fFlags & F_IS_STARTED) != 0) { 24095531d1eSJérôme Duval BMediaRoster* roster = BMediaRoster::Roster(); 241812fde99SAxel Dörfler if (roster == NULL) { 24295531d1eSJérôme Duval TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n"); 24395531d1eSJérôme Duval return; 24495531d1eSJérôme Duval } 24595531d1eSJérôme Duval 246d6105cedSbeveloper roster->StopNode(fPlayerNode->Node(), 0, true); 24795531d1eSJérôme Duval 248df42a7b5Sbeveloper atomic_and(&fFlags, ~F_IS_STARTED); 249df42a7b5Sbeveloper } 250df42a7b5Sbeveloper 251a0703a47Sbeveloper if (block) { 252a0703a47Sbeveloper // wait until the node is stopped 253812fde99SAxel Dörfler int tries; 254812fde99SAxel Dörfler for (tries = 250; fPlayerNode->IsPlaying() && tries != 0; tries--) 255a0703a47Sbeveloper snooze(2000); 256a0703a47Sbeveloper 2576813f2c7SIngo Weinhold DEBUG_ONLY(if (tries == 0) 258812fde99SAxel Dörfler TRACE("BSoundPlayer::Stop: waiting for node stop failed\n")); 259a0703a47Sbeveloper 260812fde99SAxel Dörfler // Wait until all buffers on the way to the physical output have been 261812fde99SAxel Dörfler // played 262df42a7b5Sbeveloper snooze(Latency() + 2000); 263a0703a47Sbeveloper } 26495096991SJérôme Duval 26595096991SJérôme Duval if (fNotifierFunc) 26695096991SJérôme Duval fNotifierFunc(fCookie, B_STOPPED, this); 26795096991SJérôme Duval 26852a38012Sejakowatz } 26952a38012Sejakowatz 270df42a7b5Sbeveloper 271df42a7b5Sbeveloper bigtime_t 272df42a7b5Sbeveloper BSoundPlayer::Latency() 273df42a7b5Sbeveloper { 274df42a7b5Sbeveloper CALLED(); 275df42a7b5Sbeveloper 276df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 277df42a7b5Sbeveloper return 0; 278df42a7b5Sbeveloper 279df42a7b5Sbeveloper BMediaRoster *roster = BMediaRoster::Roster(); 280df42a7b5Sbeveloper if (!roster) { 281df42a7b5Sbeveloper TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n"); 282df42a7b5Sbeveloper return 0; 283df42a7b5Sbeveloper } 284df42a7b5Sbeveloper 285df42a7b5Sbeveloper bigtime_t latency; 286df42a7b5Sbeveloper status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency); 287df42a7b5Sbeveloper if (err != B_OK) { 288812fde99SAxel Dörfler TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err, 289812fde99SAxel Dörfler strerror(err)); 290df42a7b5Sbeveloper return 0; 291df42a7b5Sbeveloper } 292df42a7b5Sbeveloper 29340c2c00aSbeveloper TRACE("BSoundPlayer::Latency: latency is %Ld\n", latency); 29440c2c00aSbeveloper 295df42a7b5Sbeveloper return latency; 296df42a7b5Sbeveloper } 297df42a7b5Sbeveloper 298df42a7b5Sbeveloper 299df42a7b5Sbeveloper void 3004ed344afSAxel Dörfler BSoundPlayer::SetHasData(bool hasData) 301df42a7b5Sbeveloper { 302df42a7b5Sbeveloper CALLED(); 3034ed344afSAxel Dörfler if (hasData) 304df42a7b5Sbeveloper atomic_or(&fFlags, F_HAS_DATA); 305df42a7b5Sbeveloper else 306df42a7b5Sbeveloper atomic_and(&fFlags, ~F_HAS_DATA); 307df42a7b5Sbeveloper } 308df42a7b5Sbeveloper 309df42a7b5Sbeveloper 310812fde99SAxel Dörfler bool 311df42a7b5Sbeveloper BSoundPlayer::HasData() 312df42a7b5Sbeveloper { 313df42a7b5Sbeveloper CALLED(); 3144ed344afSAxel Dörfler return (atomic_get(&fFlags) & F_HAS_DATA) != 0; 315df42a7b5Sbeveloper } 316df42a7b5Sbeveloper 317df42a7b5Sbeveloper 31852a38012Sejakowatz BSoundPlayer::BufferPlayerFunc 31952a38012Sejakowatz BSoundPlayer::BufferPlayer() const 32052a38012Sejakowatz { 32152a38012Sejakowatz CALLED(); 322d6105cedSbeveloper return fPlayBufferFunc; 32352a38012Sejakowatz } 32452a38012Sejakowatz 325df42a7b5Sbeveloper 326df42a7b5Sbeveloper void 327812fde99SAxel Dörfler BSoundPlayer::SetBufferPlayer(BufferPlayerFunc playerFunction) 32852a38012Sejakowatz { 32952a38012Sejakowatz CALLED(); 330812fde99SAxel Dörfler BAutolock _(fLocker); 331812fde99SAxel Dörfler 332812fde99SAxel Dörfler fPlayBufferFunc = playerFunction; 33352a38012Sejakowatz } 33452a38012Sejakowatz 335df42a7b5Sbeveloper 33652a38012Sejakowatz BSoundPlayer::EventNotifierFunc 33752a38012Sejakowatz BSoundPlayer::EventNotifier() const 33852a38012Sejakowatz { 33952a38012Sejakowatz CALLED(); 340d6105cedSbeveloper return fNotifierFunc; 34152a38012Sejakowatz } 34252a38012Sejakowatz 343df42a7b5Sbeveloper 344812fde99SAxel Dörfler void 345812fde99SAxel Dörfler BSoundPlayer::SetNotifier(EventNotifierFunc eventNotifierFunction) 34652a38012Sejakowatz { 34752a38012Sejakowatz CALLED(); 348812fde99SAxel Dörfler BAutolock _(fLocker); 349812fde99SAxel Dörfler 350812fde99SAxel Dörfler fNotifierFunc = eventNotifierFunction; 35152a38012Sejakowatz } 35252a38012Sejakowatz 353df42a7b5Sbeveloper 35452a38012Sejakowatz void* 35552a38012Sejakowatz BSoundPlayer::Cookie() const 35652a38012Sejakowatz { 35752a38012Sejakowatz CALLED(); 358d6105cedSbeveloper return fCookie; 35952a38012Sejakowatz } 36052a38012Sejakowatz 361df42a7b5Sbeveloper 36252a38012Sejakowatz void 36352a38012Sejakowatz BSoundPlayer::SetCookie(void *cookie) 36452a38012Sejakowatz { 36552a38012Sejakowatz CALLED(); 366812fde99SAxel Dörfler BAutolock _(fLocker); 367812fde99SAxel Dörfler 368d6105cedSbeveloper fCookie = cookie; 36952a38012Sejakowatz } 37052a38012Sejakowatz 371df42a7b5Sbeveloper 372df42a7b5Sbeveloper void 373812fde99SAxel Dörfler BSoundPlayer::SetCallbacks(BufferPlayerFunc playerFunction, 374812fde99SAxel Dörfler EventNotifierFunc eventNotifierFunction, void* cookie) 37552a38012Sejakowatz { 37652a38012Sejakowatz CALLED(); 377812fde99SAxel Dörfler BAutolock _(fLocker); 378812fde99SAxel Dörfler 379812fde99SAxel Dörfler SetBufferPlayer(playerFunction); 380812fde99SAxel Dörfler SetNotifier(eventNotifierFunction); 38152a38012Sejakowatz SetCookie(cookie); 38252a38012Sejakowatz } 38352a38012Sejakowatz 38452a38012Sejakowatz 385812fde99SAxel Dörfler /*! The BeBook is inaccurate about the meaning of this function. 386812fde99SAxel Dörfler The probably best interpretation is to return the time that 387812fde99SAxel Dörfler has elapsed since playing was started, whichs seems to match 388812fde99SAxel Dörfler "CurrentTime() returns the current media time" 389df42a7b5Sbeveloper */ 39052a38012Sejakowatz bigtime_t 39152a38012Sejakowatz BSoundPlayer::CurrentTime() 39252a38012Sejakowatz { 393df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 394df42a7b5Sbeveloper return 0; 39595531d1eSJérôme Duval 396df42a7b5Sbeveloper return fPlayerNode->CurrentTime(); 39752a38012Sejakowatz } 39852a38012Sejakowatz 39952a38012Sejakowatz 400812fde99SAxel Dörfler /*! Returns the current performance time of the sound player node 401812fde99SAxel Dörfler being used by the BSoundPlayer. Will return B_ERROR if the 402812fde99SAxel Dörfler BSoundPlayer object hasn't been properly initialized. 403df42a7b5Sbeveloper */ 40452a38012Sejakowatz bigtime_t 40552a38012Sejakowatz BSoundPlayer::PerformanceTime() 40652a38012Sejakowatz { 407df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 40852a38012Sejakowatz return (bigtime_t) B_ERROR; 40995531d1eSJérôme Duval 410d6105cedSbeveloper return fPlayerNode->TimeSource()->Now(); 41152a38012Sejakowatz } 41252a38012Sejakowatz 41352a38012Sejakowatz 41452a38012Sejakowatz status_t 41552a38012Sejakowatz BSoundPlayer::Preroll() 41652a38012Sejakowatz { 41795531d1eSJérôme Duval CALLED(); 41852a38012Sejakowatz 419df42a7b5Sbeveloper if ((fFlags & F_NODES_CONNECTED) == 0) 420df42a7b5Sbeveloper return B_NO_INIT; 421df42a7b5Sbeveloper 42295531d1eSJérôme Duval BMediaRoster* roster = BMediaRoster::Roster(); 423812fde99SAxel Dörfler if (roster == NULL) { 42495531d1eSJérôme Duval TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n"); 42595531d1eSJérôme Duval return B_ERROR; 42695531d1eSJérôme Duval } 42795531d1eSJérôme Duval 428d6105cedSbeveloper status_t err = roster->PrerollNode(fMediaOutput.node); 42995531d1eSJérôme Duval if (err != B_OK) { 430812fde99SAxel Dörfler TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %ld (%s)\n", 431812fde99SAxel Dörfler err, strerror(err)); 432df42a7b5Sbeveloper return err; 43395531d1eSJérôme Duval } 43495531d1eSJérôme Duval 435df42a7b5Sbeveloper return B_OK; 43652a38012Sejakowatz } 43752a38012Sejakowatz 43852a38012Sejakowatz 43952a38012Sejakowatz BSoundPlayer::play_id 4409b9aa75aSMichael Lotz BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime) 44152a38012Sejakowatz { 4429b9aa75aSMichael Lotz return StartPlaying(sound, atTime, 1.0); 44352a38012Sejakowatz } 44452a38012Sejakowatz 44552a38012Sejakowatz 44652a38012Sejakowatz BSoundPlayer::play_id 4479b9aa75aSMichael Lotz BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime, float withVolume) 44852a38012Sejakowatz { 4499b9aa75aSMichael Lotz CALLED(); 4509b9aa75aSMichael Lotz 4519b9aa75aSMichael Lotz // TODO: support the at_time and with_volume parameters 4524ed344afSAxel Dörfler playing_sound* item = (playing_sound*)malloc(sizeof(playing_sound)); 4539b9aa75aSMichael Lotz if (item == NULL) 4549b9aa75aSMichael Lotz return B_NO_MEMORY; 4559b9aa75aSMichael Lotz 4569b9aa75aSMichael Lotz item->current_offset = 0; 4579b9aa75aSMichael Lotz item->sound = sound; 4589b9aa75aSMichael Lotz item->id = atomic_add(&sCurrentPlayID, 1); 4599b9aa75aSMichael Lotz item->delta = 0; 4609b9aa75aSMichael Lotz item->rate = 0; 4619b9aa75aSMichael Lotz item->volume = withVolume; 4629b9aa75aSMichael Lotz 4639b9aa75aSMichael Lotz if (!fLocker.Lock()) { 4649b9aa75aSMichael Lotz free(item); 4659b9aa75aSMichael Lotz return B_ERROR; 4669b9aa75aSMichael Lotz } 4679b9aa75aSMichael Lotz 4686fb91db7SMichael Lotz sound->AcquireRef(); 4699b9aa75aSMichael Lotz item->next = fPlayingSounds; 4709b9aa75aSMichael Lotz fPlayingSounds = item; 4719b9aa75aSMichael Lotz fLocker.Unlock(); 4729b9aa75aSMichael Lotz 4739b9aa75aSMichael Lotz SetHasData(true); 4749b9aa75aSMichael Lotz return item->id; 47552a38012Sejakowatz } 47652a38012Sejakowatz 47752a38012Sejakowatz 47852a38012Sejakowatz status_t 4799b9aa75aSMichael Lotz BSoundPlayer::SetSoundVolume(play_id id, float newVolume) 48052a38012Sejakowatz { 4819b9aa75aSMichael Lotz CALLED(); 4829b9aa75aSMichael Lotz if (!fLocker.Lock()) 4839b9aa75aSMichael Lotz return B_ERROR; 48452a38012Sejakowatz 4854ed344afSAxel Dörfler playing_sound *item = fPlayingSounds; 4869b9aa75aSMichael Lotz while (item) { 4879b9aa75aSMichael Lotz if (item->id == id) { 4889b9aa75aSMichael Lotz item->volume = newVolume; 4899b9aa75aSMichael Lotz fLocker.Unlock(); 49052a38012Sejakowatz return B_OK; 49152a38012Sejakowatz } 49252a38012Sejakowatz 4939b9aa75aSMichael Lotz item = item->next; 4949b9aa75aSMichael Lotz } 4959b9aa75aSMichael Lotz 4969b9aa75aSMichael Lotz fLocker.Unlock(); 4979b9aa75aSMichael Lotz return B_ENTRY_NOT_FOUND; 4989b9aa75aSMichael Lotz } 4999b9aa75aSMichael Lotz 50052a38012Sejakowatz 50152a38012Sejakowatz bool 50252a38012Sejakowatz BSoundPlayer::IsPlaying(play_id id) 50352a38012Sejakowatz { 5049b9aa75aSMichael Lotz CALLED(); 5059b9aa75aSMichael Lotz if (!fLocker.Lock()) 5069b9aa75aSMichael Lotz return B_ERROR; 50752a38012Sejakowatz 5084ed344afSAxel Dörfler playing_sound *item = fPlayingSounds; 5099b9aa75aSMichael Lotz while (item) { 5109b9aa75aSMichael Lotz if (item->id == id) { 5119b9aa75aSMichael Lotz fLocker.Unlock(); 51252a38012Sejakowatz return true; 51352a38012Sejakowatz } 51452a38012Sejakowatz 5159b9aa75aSMichael Lotz item = item->next; 5169b9aa75aSMichael Lotz } 5179b9aa75aSMichael Lotz 5189b9aa75aSMichael Lotz fLocker.Unlock(); 5199b9aa75aSMichael Lotz return false; 5209b9aa75aSMichael Lotz } 5219b9aa75aSMichael Lotz 52252a38012Sejakowatz 52352a38012Sejakowatz status_t 52452a38012Sejakowatz BSoundPlayer::StopPlaying(play_id id) 52552a38012Sejakowatz { 5269b9aa75aSMichael Lotz CALLED(); 5279b9aa75aSMichael Lotz if (!fLocker.Lock()) 5289b9aa75aSMichael Lotz return B_ERROR; 5299b9aa75aSMichael Lotz 5304ed344afSAxel Dörfler playing_sound** link = &fPlayingSounds; 5314ed344afSAxel Dörfler playing_sound* item = fPlayingSounds; 532812fde99SAxel Dörfler 533812fde99SAxel Dörfler while (item != NULL) { 5349b9aa75aSMichael Lotz if (item->id == id) { 5359b9aa75aSMichael Lotz *link = item->next; 5369b9aa75aSMichael Lotz sem_id waitSem = item->wait_sem; 5376fb91db7SMichael Lotz item->sound->ReleaseRef(); 5389b9aa75aSMichael Lotz free(item); 5399b9aa75aSMichael Lotz fLocker.Unlock(); 5409b9aa75aSMichael Lotz 541812fde99SAxel Dörfler _NotifySoundDone(id, true); 5429b9aa75aSMichael Lotz if (waitSem >= 0) 5439b9aa75aSMichael Lotz release_sem(waitSem); 54452a38012Sejakowatz 54552a38012Sejakowatz return B_OK; 54652a38012Sejakowatz } 54752a38012Sejakowatz 5489b9aa75aSMichael Lotz link = &item->next; 5499b9aa75aSMichael Lotz item = item->next; 5509b9aa75aSMichael Lotz } 5519b9aa75aSMichael Lotz 5529b9aa75aSMichael Lotz fLocker.Unlock(); 5539b9aa75aSMichael Lotz return B_ENTRY_NOT_FOUND; 5549b9aa75aSMichael Lotz } 5559b9aa75aSMichael Lotz 55652a38012Sejakowatz 55752a38012Sejakowatz status_t 55852a38012Sejakowatz BSoundPlayer::WaitForSound(play_id id) 55952a38012Sejakowatz { 5609b9aa75aSMichael Lotz CALLED(); 5619b9aa75aSMichael Lotz if (!fLocker.Lock()) 5629b9aa75aSMichael Lotz return B_ERROR; 56352a38012Sejakowatz 5644ed344afSAxel Dörfler playing_sound* item = fPlayingSounds; 565812fde99SAxel Dörfler while (item != NULL) { 5669b9aa75aSMichael Lotz if (item->id == id) { 5679b9aa75aSMichael Lotz sem_id waitSem = item->wait_sem; 5689b9aa75aSMichael Lotz if (waitSem < 0) 5699b9aa75aSMichael Lotz waitSem = item->wait_sem = create_sem(0, "wait for sound"); 5709b9aa75aSMichael Lotz 5719b9aa75aSMichael Lotz fLocker.Unlock(); 5729b9aa75aSMichael Lotz return acquire_sem(waitSem); 5739b9aa75aSMichael Lotz } 5749b9aa75aSMichael Lotz 5759b9aa75aSMichael Lotz item = item->next; 5769b9aa75aSMichael Lotz } 5779b9aa75aSMichael Lotz 5789b9aa75aSMichael Lotz fLocker.Unlock(); 5799b9aa75aSMichael Lotz return B_ENTRY_NOT_FOUND; 58052a38012Sejakowatz } 58152a38012Sejakowatz 58252a38012Sejakowatz 58352a38012Sejakowatz float 58452a38012Sejakowatz BSoundPlayer::Volume() 58552a38012Sejakowatz { 58652a38012Sejakowatz CALLED(); 587adc3b786SJérôme Duval return pow(10.0, VolumeDB(true) / 20.0); 58852a38012Sejakowatz } 58952a38012Sejakowatz 59052a38012Sejakowatz 59152a38012Sejakowatz void 592812fde99SAxel Dörfler BSoundPlayer::SetVolume(float newVolume) 59352a38012Sejakowatz { 59452a38012Sejakowatz CALLED(); 595812fde99SAxel Dörfler SetVolumeDB(20.0 * log10(newVolume)); 59652a38012Sejakowatz } 59752a38012Sejakowatz 59852a38012Sejakowatz 59952a38012Sejakowatz float 60052a38012Sejakowatz BSoundPlayer::VolumeDB(bool forcePoll) 60152a38012Sejakowatz { 60252a38012Sejakowatz CALLED(); 603d6105cedSbeveloper if (!fVolumeSlider) 604df42a7b5Sbeveloper return -94.0f; // silence 60537ed595fSJérôme Duval 606812fde99SAxel Dörfler if (!forcePoll && system_time() - fLastVolumeUpdate < 500000) 607df42a7b5Sbeveloper return fVolumeDB; 608adc3b786SJérôme Duval 609d6105cedSbeveloper int32 count = fVolumeSlider->CountChannels(); 610adc3b786SJérôme Duval float values[count]; 611adc3b786SJérôme Duval size_t size = count * sizeof(float); 612d6105cedSbeveloper fVolumeSlider->GetValue(&values, &size, NULL); 613d6105cedSbeveloper fLastVolumeUpdate = system_time(); 614df42a7b5Sbeveloper fVolumeDB = values[0]; 615adc3b786SJérôme Duval 616adc3b786SJérôme Duval return values[0]; 61752a38012Sejakowatz } 61852a38012Sejakowatz 61952a38012Sejakowatz 62052a38012Sejakowatz void 621812fde99SAxel Dörfler BSoundPlayer::SetVolumeDB(float volumeDB) 62252a38012Sejakowatz { 62352a38012Sejakowatz CALLED(); 624d6105cedSbeveloper if (!fVolumeSlider) 62537ed595fSJérôme Duval return; 62637ed595fSJérôme Duval 627812fde99SAxel Dörfler float minDB = fVolumeSlider->MinValue(); 628812fde99SAxel Dörfler float maxDB = fVolumeSlider->MaxValue(); 629812fde99SAxel Dörfler if (volumeDB < minDB) 630812fde99SAxel Dörfler volumeDB = minDB; 631812fde99SAxel Dörfler if (volumeDB > maxDB) 632812fde99SAxel Dörfler volumeDB = maxDB; 633adc3b786SJérôme Duval 634d6105cedSbeveloper int count = fVolumeSlider->CountChannels(); 63537ed595fSJérôme Duval float values[count]; 636d6105cedSbeveloper for (int i = 0; i < count; i++) 637812fde99SAxel Dörfler values[i] = volumeDB; 638d6105cedSbeveloper fVolumeSlider->SetValue(values, sizeof(float) * count, 0); 639d6105cedSbeveloper 640812fde99SAxel Dörfler fVolumeDB = volumeDB; 641d6105cedSbeveloper fLastVolumeUpdate = system_time(); 64252a38012Sejakowatz } 64352a38012Sejakowatz 64452a38012Sejakowatz 64552a38012Sejakowatz status_t 646812fde99SAxel Dörfler BSoundPlayer::GetVolumeInfo(media_node* _node, int32* _parameterID, 647812fde99SAxel Dörfler float* _minDB, float* _maxDB) 64852a38012Sejakowatz { 64937ed595fSJérôme Duval CALLED(); 650812fde99SAxel Dörfler if (fVolumeSlider == NULL) 651d6105cedSbeveloper return B_NO_INIT; 65252a38012Sejakowatz 653812fde99SAxel Dörfler if (_node != NULL) 654812fde99SAxel Dörfler *_node = fMediaInput.node; 655812fde99SAxel Dörfler if (_parameterID != NULL) 656812fde99SAxel Dörfler *_parameterID = fVolumeSlider->ID(); 657812fde99SAxel Dörfler if (_minDB != NULL) 658812fde99SAxel Dörfler *_minDB = fVolumeSlider->MinValue(); 659812fde99SAxel Dörfler if (_maxDB != NULL) 660812fde99SAxel Dörfler *_maxDB = fVolumeSlider->MaxValue(); 661812fde99SAxel Dörfler 66252a38012Sejakowatz return B_OK; 66352a38012Sejakowatz } 66452a38012Sejakowatz 66552a38012Sejakowatz 666812fde99SAxel Dörfler // #pragma mark - protected BSoundPlayer 66752a38012Sejakowatz 668df42a7b5Sbeveloper 66952a38012Sejakowatz void 670812fde99SAxel Dörfler BSoundPlayer::SetInitError(status_t error) 67152a38012Sejakowatz { 67252a38012Sejakowatz CALLED(); 673812fde99SAxel Dörfler fInitStatus = error; 67452a38012Sejakowatz } 67552a38012Sejakowatz 67652a38012Sejakowatz 677812fde99SAxel Dörfler // #pragma mark - private BSoundPlayer 678812fde99SAxel Dörfler 67952a38012Sejakowatz 6809b9aa75aSMichael Lotz void 6819b9aa75aSMichael Lotz BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size, 6829b9aa75aSMichael Lotz const media_raw_audio_format &format) 6839b9aa75aSMichael Lotz { 6849b9aa75aSMichael Lotz // TODO: support more than one sound and make use of the format parameter 6859b9aa75aSMichael Lotz BSoundPlayer *player = (BSoundPlayer *)cookie; 6869b9aa75aSMichael Lotz if (!player->fLocker.Lock()) { 6879b9aa75aSMichael Lotz memset(buffer, 0, size); 6889b9aa75aSMichael Lotz return; 6899b9aa75aSMichael Lotz } 6909b9aa75aSMichael Lotz 6914ed344afSAxel Dörfler playing_sound *sound = player->fPlayingSounds; 6929b9aa75aSMichael Lotz if (sound == NULL) { 6939b9aa75aSMichael Lotz player->SetHasData(false); 6949b9aa75aSMichael Lotz player->fLocker.Unlock(); 6959b9aa75aSMichael Lotz memset(buffer, 0, size); 6969b9aa75aSMichael Lotz return; 6979b9aa75aSMichael Lotz } 6989b9aa75aSMichael Lotz 6999b9aa75aSMichael Lotz size_t used = 0; 7009b9aa75aSMichael Lotz if (!sound->sound->GetDataAt(sound->current_offset, buffer, size, &used)) { 7019b9aa75aSMichael Lotz // will take care of removing the item and notifying others 7029b9aa75aSMichael Lotz player->StopPlaying(sound->id); 7039b9aa75aSMichael Lotz player->fLocker.Unlock(); 7049b9aa75aSMichael Lotz memset(buffer, 0, size); 7059b9aa75aSMichael Lotz return; 7069b9aa75aSMichael Lotz } 7079b9aa75aSMichael Lotz 7089b9aa75aSMichael Lotz sound->current_offset += used; 7099b9aa75aSMichael Lotz player->fLocker.Unlock(); 7109b9aa75aSMichael Lotz 7119b9aa75aSMichael Lotz if (used < size) 7129b9aa75aSMichael Lotz memset((uint8 *)buffer + used, 0, size - used); 7139b9aa75aSMichael Lotz } 7149b9aa75aSMichael Lotz 7159b9aa75aSMichael Lotz 71652a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_0(void*, ...) { return B_ERROR; } 71752a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_1(void*, ...) { return B_ERROR; } 71852a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_2(void*, ...) { return B_ERROR; } 71952a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_3(void*, ...) { return B_ERROR; } 72052a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_4(void*, ...) { return B_ERROR; } 72152a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_5(void*, ...) { return B_ERROR; } 72252a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_6(void*, ...) { return B_ERROR; } 72352a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_7(void*, ...) { return B_ERROR; } 72452a38012Sejakowatz 72552a38012Sejakowatz 72652a38012Sejakowatz void 727812fde99SAxel Dörfler BSoundPlayer::_Init(const media_node* node, 728812fde99SAxel Dörfler const media_multi_audio_format* format, const char* name, 729812fde99SAxel Dörfler const media_input* input, BufferPlayerFunc playerFunction, 730812fde99SAxel Dörfler EventNotifierFunc eventNotifierFunction, void* cookie) 73152a38012Sejakowatz { 7329b9aa75aSMichael Lotz CALLED(); 733812fde99SAxel Dörfler fPlayingSounds = NULL; 734812fde99SAxel Dörfler fWaitingSounds = NULL; 735812fde99SAxel Dörfler 736812fde99SAxel Dörfler fPlayerNode = NULL; 737812fde99SAxel Dörfler if (playerFunction == NULL) { 738812fde99SAxel Dörfler fPlayBufferFunc = _SoundPlayBufferFunc; 739812fde99SAxel Dörfler fCookie = this; 740812fde99SAxel Dörfler } else { 741812fde99SAxel Dörfler fPlayBufferFunc = playerFunction; 742812fde99SAxel Dörfler fCookie = cookie; 743812fde99SAxel Dörfler } 744812fde99SAxel Dörfler 745812fde99SAxel Dörfler fNotifierFunc = eventNotifierFunction; 746812fde99SAxel Dörfler fVolumeDB = 0.0f; 747812fde99SAxel Dörfler fFlags = 0; 748812fde99SAxel Dörfler fInitStatus = B_ERROR; 749812fde99SAxel Dörfler fParameterWeb = NULL; 750812fde99SAxel Dörfler fVolumeSlider = NULL; 751812fde99SAxel Dörfler fLastVolumeUpdate = 0; 752812fde99SAxel Dörfler 753812fde99SAxel Dörfler BMediaRoster* roster = BMediaRoster::Roster(); 754812fde99SAxel Dörfler if (roster == NULL) { 755812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't get BMediaRoster\n"); 756812fde99SAxel Dörfler return; 757812fde99SAxel Dörfler } 758812fde99SAxel Dörfler 759812fde99SAxel Dörfler // The inputNode that our player node will be 760812fde99SAxel Dörfler // connected with is either supplied by the user 761812fde99SAxel Dörfler // or the system audio mixer 762812fde99SAxel Dörfler media_node inputNode; 763812fde99SAxel Dörfler if (node) { 764812fde99SAxel Dörfler inputNode = *node; 765812fde99SAxel Dörfler } else { 766812fde99SAxel Dörfler fInitStatus = roster->GetAudioMixer(&inputNode); 767812fde99SAxel Dörfler if (fInitStatus != B_OK) { 768812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't GetAudioMixer\n"); 769812fde99SAxel Dörfler return; 770812fde99SAxel Dörfler } 771812fde99SAxel Dörfler fFlags |= F_MUST_RELEASE_MIXER; 772812fde99SAxel Dörfler } 773812fde99SAxel Dörfler 774812fde99SAxel Dörfler media_output _output; 775812fde99SAxel Dörfler media_input _input; 776812fde99SAxel Dörfler int32 inputCount; 777812fde99SAxel Dörfler int32 outputCount; 778812fde99SAxel Dörfler media_format tryFormat; 779812fde99SAxel Dörfler 780812fde99SAxel Dörfler // Create the player node and register it 7814ed344afSAxel Dörfler fPlayerNode = new BPrivate::SoundPlayNode(name, this); 782812fde99SAxel Dörfler fInitStatus = roster->RegisterNode(fPlayerNode); 783812fde99SAxel Dörfler if (fInitStatus != B_OK) { 784812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't RegisterNode: %s\n", 785812fde99SAxel Dörfler strerror(fInitStatus)); 786812fde99SAxel Dörfler return; 787812fde99SAxel Dörfler } 788812fde99SAxel Dörfler 789812fde99SAxel Dörfler // set the producer's time source to be the "default" time source, 790812fde99SAxel Dörfler // which the system audio mixer uses too. 791812fde99SAxel Dörfler media_node timeSource; 792812fde99SAxel Dörfler fInitStatus = roster->GetTimeSource(&timeSource); 793812fde99SAxel Dörfler if (fInitStatus != B_OK) { 794812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't GetTimeSource: %s\n", 795812fde99SAxel Dörfler strerror(fInitStatus)); 796812fde99SAxel Dörfler return; 797812fde99SAxel Dörfler } 798812fde99SAxel Dörfler fInitStatus = roster->SetTimeSourceFor(fPlayerNode->Node().node, 799812fde99SAxel Dörfler timeSource.node); 800812fde99SAxel Dörfler if (fInitStatus != B_OK) { 801812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't SetTimeSourceFor: %s\n", 802812fde99SAxel Dörfler strerror(fInitStatus)); 803812fde99SAxel Dörfler return; 804812fde99SAxel Dörfler } 805812fde99SAxel Dörfler 806812fde99SAxel Dörfler // find a free media_input 807812fde99SAxel Dörfler if (!input) { 808812fde99SAxel Dörfler fInitStatus = roster->GetFreeInputsFor(inputNode, &_input, 1, 809812fde99SAxel Dörfler &inputCount, B_MEDIA_RAW_AUDIO); 810812fde99SAxel Dörfler if (fInitStatus != B_OK) { 811812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't GetFreeInputsFor: %s\n", 812812fde99SAxel Dörfler strerror(fInitStatus)); 813812fde99SAxel Dörfler return; 814812fde99SAxel Dörfler } 815812fde99SAxel Dörfler if (inputCount < 1) { 816812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't find a free input\n"); 817812fde99SAxel Dörfler fInitStatus = B_ERROR; 818812fde99SAxel Dörfler return; 819812fde99SAxel Dörfler } 820812fde99SAxel Dörfler } else { 821812fde99SAxel Dörfler _input = *input; 822812fde99SAxel Dörfler } 823812fde99SAxel Dörfler 824812fde99SAxel Dörfler // find a free media_output 825812fde99SAxel Dörfler fInitStatus = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1, 826812fde99SAxel Dörfler &outputCount, B_MEDIA_RAW_AUDIO); 827812fde99SAxel Dörfler if (fInitStatus != B_OK) { 828812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't GetFreeOutputsFor: %s\n", 829812fde99SAxel Dörfler strerror(fInitStatus)); 830812fde99SAxel Dörfler return; 831812fde99SAxel Dörfler } 832812fde99SAxel Dörfler if (outputCount < 1) { 833812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't find a free output\n"); 834812fde99SAxel Dörfler fInitStatus = B_ERROR; 835812fde99SAxel Dörfler return; 836812fde99SAxel Dörfler } 837812fde99SAxel Dörfler 838812fde99SAxel Dörfler // Set an appropriate run mode for the producer 839812fde99SAxel Dörfler fInitStatus = roster->SetRunModeNode(fPlayerNode->Node(), 840812fde99SAxel Dörfler BMediaNode::B_INCREASE_LATENCY); 841812fde99SAxel Dörfler if (fInitStatus != B_OK) { 842812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't SetRunModeNode: %s\n", 843812fde99SAxel Dörfler strerror(fInitStatus)); 844812fde99SAxel Dörfler return; 845812fde99SAxel Dörfler } 846812fde99SAxel Dörfler 847812fde99SAxel Dörfler // setup our requested format (can still have many wildcards) 848812fde99SAxel Dörfler tryFormat.type = B_MEDIA_RAW_AUDIO; 849812fde99SAxel Dörfler tryFormat.u.raw_audio = *format; 850812fde99SAxel Dörfler 851812fde99SAxel Dörfler #if DEBUG > 0 852812fde99SAxel Dörfler char buf[100]; 853812fde99SAxel Dörfler string_for_format(tryFormat, buf, sizeof(buf)); 854812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: trying to connect with format %s\n", buf); 855812fde99SAxel Dörfler #endif 856812fde99SAxel Dörfler 857812fde99SAxel Dörfler // and connect the nodes 858812fde99SAxel Dörfler fInitStatus = roster->Connect(_output.source, _input.destination, 859812fde99SAxel Dörfler &tryFormat, &fMediaOutput, &fMediaInput); 860812fde99SAxel Dörfler if (fInitStatus != B_OK) { 861812fde99SAxel Dörfler TRACE("BSoundPlayer::_Init: Couldn't Connect: %s\n", 862812fde99SAxel Dörfler strerror(fInitStatus)); 863812fde99SAxel Dörfler return; 864812fde99SAxel Dörfler } 865812fde99SAxel Dörfler 866812fde99SAxel Dörfler fFlags |= F_NODES_CONNECTED; 867812fde99SAxel Dörfler 868812fde99SAxel Dörfler _GetVolumeSlider(); 869812fde99SAxel Dörfler 870812fde99SAxel Dörfler TRACE("BSoundPlayer node %ld has timesource %ld\n", 871812fde99SAxel Dörfler fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node); 87252a38012Sejakowatz } 87352a38012Sejakowatz 87452a38012Sejakowatz 87552a38012Sejakowatz void 876812fde99SAxel Dörfler BSoundPlayer::_NotifySoundDone(play_id id, bool gotToPlay) 877812fde99SAxel Dörfler { 878812fde99SAxel Dörfler CALLED(); 87915c81466SAxel Dörfler Notify(B_SOUND_DONE, id, gotToPlay); 880812fde99SAxel Dörfler } 881812fde99SAxel Dörfler 882812fde99SAxel Dörfler 883812fde99SAxel Dörfler void 884812fde99SAxel Dörfler BSoundPlayer::_GetVolumeSlider() 88552a38012Sejakowatz { 886adc3b786SJérôme Duval CALLED(); 887adc3b786SJérôme Duval 888d6105cedSbeveloper ASSERT(fVolumeSlider == NULL); 889d6105cedSbeveloper 89037ed595fSJérôme Duval BMediaRoster *roster = BMediaRoster::CurrentRoster(); 89140c2c00aSbeveloper if (!roster) { 892812fde99SAxel Dörfler TRACE("BSoundPlayer::_GetVolumeSlider failed to get BMediaRoster"); 89337ed595fSJérôme Duval return; 89440c2c00aSbeveloper } 895d6105cedSbeveloper 89640c2c00aSbeveloper if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) { 897812fde99SAxel Dörfler TRACE("BSoundPlayer::_GetVolumeSlider couldn't get parameter web"); 89837ed595fSJérôme Duval return; 89940c2c00aSbeveloper } 900d6105cedSbeveloper 901d6105cedSbeveloper int count = fParameterWeb->CountParameters(); 902d6105cedSbeveloper for (int i = 0; i < count; i++) { 903df42a7b5Sbeveloper BParameter *parameter = fParameterWeb->ParameterAt(i); 904d6105cedSbeveloper if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER) 90537ed595fSJérôme Duval continue; 906df42a7b5Sbeveloper if ((parameter->ID() >> 16) != fMediaInput.destination.id) 907d6105cedSbeveloper continue; 908d6105cedSbeveloper if (strcmp(parameter->Kind(), B_GAIN) != 0) 909d6105cedSbeveloper continue; 910d6105cedSbeveloper fVolumeSlider = (BContinuousParameter *)parameter; 91137ed595fSJérôme Duval break; 91237ed595fSJérôme Duval } 91340c2c00aSbeveloper 91440c2c00aSbeveloper #if DEBUG >0 91540c2c00aSbeveloper if (!fVolumeSlider) { 916812fde99SAxel Dörfler TRACE("BSoundPlayer::_GetVolumeSlider couldn't find volume control"); 91740c2c00aSbeveloper } 91840c2c00aSbeveloper #endif 91952a38012Sejakowatz } 92052a38012Sejakowatz 921d6105cedSbeveloper 922812fde99SAxel Dörfler void 92315c81466SAxel Dörfler BSoundPlayer::Notify(sound_player_notification what, ...) 92452a38012Sejakowatz { 92552a38012Sejakowatz CALLED(); 926d6105cedSbeveloper if (fLocker.Lock()) { 927d6105cedSbeveloper if (fNotifierFunc) 928d6105cedSbeveloper (*fNotifierFunc)(fCookie, what); 929d6105cedSbeveloper fLocker.Unlock(); 93052a38012Sejakowatz } 93152a38012Sejakowatz } 93252a38012Sejakowatz 93352a38012Sejakowatz 934812fde99SAxel Dörfler void 93515c81466SAxel Dörfler BSoundPlayer::PlayBuffer(void* buffer, size_t size, 936812fde99SAxel Dörfler const media_raw_audio_format& format) 93752a38012Sejakowatz { 938d6105cedSbeveloper if (fLocker.Lock()) { 939d6105cedSbeveloper if (fPlayBufferFunc) 940d6105cedSbeveloper (*fPlayBufferFunc)(fCookie, buffer, size, format); 941d6105cedSbeveloper fLocker.Unlock(); 94252a38012Sejakowatz } 94352a38012Sejakowatz } 944df42a7b5Sbeveloper 945df42a7b5Sbeveloper 946812fde99SAxel Dörfler // #pragma mark - public sound_error 947df42a7b5Sbeveloper 948df42a7b5Sbeveloper 949812fde99SAxel Dörfler sound_error::sound_error(const char* string) 950df42a7b5Sbeveloper { 951812fde99SAxel Dörfler m_str_const = string; 952df42a7b5Sbeveloper } 953df42a7b5Sbeveloper 954df42a7b5Sbeveloper 955df42a7b5Sbeveloper const char* 956bedeb04eSIngo Weinhold sound_error::what() const throw() 957df42a7b5Sbeveloper { 958df42a7b5Sbeveloper return m_str_const; 959df42a7b5Sbeveloper } 960df42a7b5Sbeveloper 961